Coverage Report

Created: 2025-07-23 08:13

/src/fontconfig/subprojects/libxml2-2.12.6/globals.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * globals.c: definition and handling of the set of global variables
3
 *            of the library
4
 *
5
 * See Copyright for the status of this software.
6
 *
7
 * Gary Pennington <Gary.Pennington@uk.sun.com>
8
 * daniel@veillard.com
9
 */
10
11
#define IN_LIBXML
12
#include "libxml.h"
13
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
18
#define XML_GLOBALS_NO_REDEFINITION
19
#include <libxml/globals.h>
20
#include <libxml/xmlerror.h>
21
#include <libxml/xmlmemory.h>
22
#include <libxml/xmlIO.h>
23
#include <libxml/HTMLparser.h>
24
#include <libxml/parser.h>
25
#include <libxml/threads.h>
26
#include <libxml/tree.h>
27
#include <libxml/SAX.h>
28
#include <libxml/SAX2.h>
29
30
#include "private/error.h"
31
#include "private/globals.h"
32
#include "private/threads.h"
33
#include "private/tree.h"
34
35
/*
36
 * Thread-local storage emulation.
37
 *
38
 * This works by replacing a global variable
39
 *
40
 *     extern xmlError xmlLastError;
41
 *
42
 * with a macro that calls a function returning a pointer to the global in
43
 * thread-local storage:
44
 *
45
 *     xmlError *__xmlLastError(void);
46
 *     #define xmlError (*__xmlLastError());
47
 *
48
 * The code can operate in a multitude of ways depending on the environment.
49
 * First we support POSIX and Windows threads. Then we support both thread-local
50
 * storage provided by the compiler and older methods like thread-specific data
51
 * (pthreads) or TlsAlloc (Windows).
52
 *
53
 * To clean up thread-local storage, we use thread-specific data on POSIX.
54
 * On Windows, we either use DllMain when compiling a DLL or a registered wait
55
 * function for static builds.
56
 */
57
58
/*
59
 * Helpful Macro
60
 */
61
#ifdef LIBXML_THREAD_ENABLED
62
99
#define IS_MAIN_THREAD (xmlIsMainThreadInternal())
63
#else
64
#define IS_MAIN_THREAD 1
65
#endif
66
67
#define XML_DECLARE_MEMBER(name, type, attrs) \
68
  type gs_##name;
69
70
struct _xmlGlobalState {
71
    int initialized;
72
73
#if defined(HAVE_WIN32_THREADS) && \
74
    defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
75
    void *threadHandle;
76
    void *waitHandle;
77
#endif
78
79
#define XML_OP XML_DECLARE_MEMBER
80
XML_GLOBALS_ALLOC
81
XML_GLOBALS_ERROR
82
XML_GLOBALS_HTML
83
XML_GLOBALS_IO
84
XML_GLOBALS_PARSER
85
XML_GLOBALS_TREE
86
#undef XML_OP
87
};
88
89
static int parserInitialized;
90
91
/*
92
 * Mutex to protect "ForNewThreads" variables
93
 */
94
static xmlMutex xmlThrDefMutex;
95
96
#ifdef LIBXML_THREAD_ENABLED
97
98
/*
99
 * On Darwin, thread-local storage destructors seem to be run before
100
 * pthread thread-specific data destructors. This causes ASan to
101
 * report a use-after-free.
102
 *
103
 * On Windows, we can't use TLS in static builds. The RegisterWait
104
 * callback would run after TLS was deallocated.
105
 */
106
#if defined(XML_THREAD_LOCAL) && \
107
    !defined(__APPLE__) && \
108
    (!defined(HAVE_WIN32_THREADS) || \
109
     !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
110
#define USE_TLS
111
#endif
112
113
#ifdef USE_TLS
114
static XML_THREAD_LOCAL xmlGlobalState globalState;
115
#endif
116
117
#ifdef HAVE_POSIX_THREADS
118
119
/*
120
 * Weak symbol hack, see threads.c
121
 */
122
#if defined(__GNUC__) && \
123
    defined(__GLIBC__) && \
124
    __GLIBC__ * 100 + __GLIBC_MINOR__ < 234
125
126
#pragma weak pthread_getspecific
127
#pragma weak pthread_setspecific
128
#pragma weak pthread_key_create
129
#pragma weak pthread_key_delete
130
#pragma weak pthread_equal
131
#pragma weak pthread_self
132
133
#define XML_PTHREAD_WEAK
134
135
static int libxml_is_threaded = -1;
136
137
#endif
138
139
/*
140
 * On POSIX, we need thread-specific data even with thread-local storage
141
 * to destroy indirect references from global state (xmlLastError) at
142
 * thread exit.
143
 */
144
static pthread_key_t globalkey;
145
static pthread_t mainthread;
146
147
#elif defined HAVE_WIN32_THREADS
148
149
#ifndef USE_TLS
150
static DWORD globalkey = TLS_OUT_OF_INDEXES;
151
#endif
152
static DWORD mainthread;
153
154
#endif /* HAVE_WIN32_THREADS */
155
156
static void
157
xmlFreeGlobalState(void *state);
158
159
#endif /* LIBXML_THREAD_ENABLED */
160
161
/************************************************************************
162
 *                  *
163
 *  All the user accessible global variables of the library   *
164
 *                  *
165
 ************************************************************************/
166
167
/*
168
 * Memory allocation routines
169
 */
170
171
#if defined(DEBUG_MEMORY_LOCATION)
172
xmlFreeFunc xmlFree = (xmlFreeFunc) xmlMemFree;
173
xmlMallocFunc xmlMalloc = (xmlMallocFunc) xmlMemMalloc;
174
xmlMallocFunc xmlMallocAtomic = (xmlMallocFunc) xmlMemMalloc;
175
xmlReallocFunc xmlRealloc = (xmlReallocFunc) xmlMemRealloc;
176
xmlStrdupFunc xmlMemStrdup = (xmlStrdupFunc) xmlMemoryStrdup;
177
#else
178
/**
179
 * xmlFree:
180
 * @mem: an already allocated block of memory
181
 *
182
 * The variable holding the libxml free() implementation
183
 */
184
xmlFreeFunc xmlFree = free;
185
/**
186
 * xmlMalloc:
187
 * @size:  the size requested in bytes
188
 *
189
 * The variable holding the libxml malloc() implementation
190
 *
191
 * Returns a pointer to the newly allocated block or NULL in case of error
192
 */
193
xmlMallocFunc xmlMalloc = malloc;
194
/**
195
 * xmlMallocAtomic:
196
 * @size:  the size requested in bytes
197
 *
198
 * The variable holding the libxml malloc() implementation for atomic
199
 * data (i.e. blocks not containing pointers), useful when using a
200
 * garbage collecting allocator.
201
 *
202
 * Returns a pointer to the newly allocated block or NULL in case of error
203
 */
204
xmlMallocFunc xmlMallocAtomic = malloc;
205
/**
206
 * xmlRealloc:
207
 * @mem: an already allocated block of memory
208
 * @size:  the new size requested in bytes
209
 *
210
 * The variable holding the libxml realloc() implementation
211
 *
212
 * Returns a pointer to the newly reallocated block or NULL in case of error
213
 */
214
xmlReallocFunc xmlRealloc = realloc;
215
/**
216
 * xmlPosixStrdup
217
 * @cur:  the input char *
218
 *
219
 * a strdup implementation with a type signature matching POSIX
220
 *
221
 * Returns a new xmlChar * or NULL
222
 */
223
static char *
224
11
xmlPosixStrdup(const char *cur) {
225
11
    return((char*) xmlCharStrdup(cur));
226
11
}
227
/**
228
 * xmlMemStrdup:
229
 * @str: a zero terminated string
230
 *
231
 * The variable holding the libxml strdup() implementation
232
 *
233
 * Returns the copy of the string or NULL in case of error
234
 */
235
xmlStrdupFunc xmlMemStrdup = xmlPosixStrdup;
236
#endif /* DEBUG_MEMORY_LOCATION */
237
238
/**
239
 * xmlBufferAllocScheme:
240
 *
241
 * DEPRECATED: Don't use.
242
 *
243
 * Global setting, default allocation policy for buffers, default is
244
 * XML_BUFFER_ALLOC_EXACT
245
 */
246
xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT;
247
static xmlBufferAllocationScheme xmlBufferAllocSchemeThrDef = XML_BUFFER_ALLOC_EXACT;
248
/**
249
 * xmlDefaultBufferSize:
250
 *
251
 * DEPRECATED: Don't use.
252
 *
253
 * Global setting, default buffer size. Default value is BASE_BUFFER_SIZE
254
 */
255
int xmlDefaultBufferSize = BASE_BUFFER_SIZE;
256
static int xmlDefaultBufferSizeThrDef = BASE_BUFFER_SIZE;
257
258
/*
259
 * Parser defaults
260
 */
261
262
/**
263
 * oldXMLWDcompatibility:
264
 *
265
 * Global setting, DEPRECATED.
266
 */
267
int oldXMLWDcompatibility = 0; /* DEPRECATED */
268
/**
269
 * xmlParserDebugEntities:
270
 *
271
 * DEPRECATED: Don't use
272
 *
273
 * Global setting, asking the parser to print out debugging information.
274
 * while handling entities.
275
 * Disabled by default
276
 */
277
int xmlParserDebugEntities = 0;
278
static int xmlParserDebugEntitiesThrDef = 0;
279
/**
280
 * xmlDoValidityCheckingDefaultValue:
281
 *
282
 * DEPRECATED: Use the modern options API with XML_PARSE_DTDVALID.
283
 *
284
 * Global setting, indicate that the parser should work in validating mode.
285
 * Disabled by default.
286
 */
287
int xmlDoValidityCheckingDefaultValue = 0;
288
static int xmlDoValidityCheckingDefaultValueThrDef = 0;
289
/**
290
 * xmlGetWarningsDefaultValue:
291
 *
292
 * DEPRECATED: Don't use
293
 *
294
 * Global setting, indicate that the DTD validation should provide warnings.
295
 * Activated by default.
296
 */
297
int xmlGetWarningsDefaultValue = 1;
298
static int xmlGetWarningsDefaultValueThrDef = 1;
299
/**
300
 * xmlLoadExtDtdDefaultValue:
301
 *
302
 * DEPRECATED: Use the modern options API with XML_PARSE_DTDLOAD.
303
 *
304
 * Global setting, indicate that the parser should load DTD while not
305
 * validating.
306
 * Disabled by default.
307
 */
308
int xmlLoadExtDtdDefaultValue = 0;
309
static int xmlLoadExtDtdDefaultValueThrDef = 0;
310
/**
311
 * xmlPedanticParserDefaultValue:
312
 *
313
 * DEPRECATED: Use the modern options API with XML_PARSE_PEDANTIC.
314
 *
315
 * Global setting, indicate that the parser be pedantic
316
 * Disabled by default.
317
 */
318
int xmlPedanticParserDefaultValue = 0;
319
static int xmlPedanticParserDefaultValueThrDef = 0;
320
/**
321
 * xmlLineNumbersDefaultValue:
322
 *
323
 * DEPRECATED: The modern options API always enables line numbers.
324
 *
325
 * Global setting, indicate that the parser should store the line number
326
 * in the content field of elements in the DOM tree.
327
 * Disabled by default since this may not be safe for old classes of
328
 * application.
329
 */
330
int xmlLineNumbersDefaultValue = 0;
331
static int xmlLineNumbersDefaultValueThrDef = 0;
332
/**
333
 * xmlKeepBlanksDefaultValue:
334
 *
335
 * DEPRECATED: Use the modern options API with XML_PARSE_NOBLANKS.
336
 *
337
 * Global setting, indicate that the parser should keep all blanks
338
 * nodes found in the content
339
 * Activated by default, this is actually needed to have the parser
340
 * conformant to the XML Recommendation, however the option is kept
341
 * for some applications since this was libxml1 default behaviour.
342
 */
343
int xmlKeepBlanksDefaultValue = 1;
344
static int xmlKeepBlanksDefaultValueThrDef = 1;
345
/**
346
 * xmlSubstituteEntitiesDefaultValue:
347
 *
348
 * DEPRECATED: Use the modern options API with XML_PARSE_NOENT.
349
 *
350
 * Global setting, indicate that the parser should not generate entity
351
 * references but replace them with the actual content of the entity
352
 * Disabled by default, this should be activated when using XPath since
353
 * the XPath data model requires entities replacement and the XPath
354
 * engine does not handle entities references transparently.
355
 */
356
int xmlSubstituteEntitiesDefaultValue = 0;
357
static int xmlSubstituteEntitiesDefaultValueThrDef = 0;
358
359
/**
360
 * xmlRegisterNodeDefaultValue:
361
 *
362
 * DEPRECATED: Don't use
363
 */
364
xmlRegisterNodeFunc xmlRegisterNodeDefaultValue = NULL;
365
static xmlRegisterNodeFunc xmlRegisterNodeDefaultValueThrDef = NULL;
366
367
/**
368
 * xmlDeregisterNodeDefaultValue:
369
 *
370
 * DEPRECATED: Don't use
371
 */
372
xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValue = NULL;
373
static xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValueThrDef = NULL;
374
375
/**
376
 * xmlParserInputBufferCreateFilenameValue:
377
 *
378
 * DEPRECATED: Don't use
379
 */
380
xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValue = NULL;
381
static xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValueThrDef = NULL;
382
383
/**
384
 * xmlOutputBufferCreateFilenameValue:
385
 *
386
 * DEPRECATED: Don't use
387
 */
388
xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValue = NULL;
389
static xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValueThrDef = NULL;
390
391
/**
392
 * xmlGenericError:
393
 *
394
 * Global setting: function used for generic error callbacks
395
 */
396
xmlGenericErrorFunc xmlGenericError = xmlGenericErrorDefaultFunc;
397
static xmlGenericErrorFunc xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc;
398
/**
399
 * xmlStructuredError:
400
 *
401
 * Global setting: function used for structured error callbacks
402
 */
403
xmlStructuredErrorFunc xmlStructuredError = NULL;
404
static xmlStructuredErrorFunc xmlStructuredErrorThrDef = NULL;
405
/**
406
 * xmlGenericErrorContext:
407
 *
408
 * Global setting passed to generic error callbacks
409
 */
410
void *xmlGenericErrorContext = NULL;
411
static void *xmlGenericErrorContextThrDef = NULL;
412
/**
413
 * xmlStructuredErrorContext:
414
 *
415
 * Global setting passed to structured error callbacks
416
 */
417
void *xmlStructuredErrorContext = NULL;
418
static void *xmlStructuredErrorContextThrDef = NULL;
419
xmlError xmlLastError;
420
421
#ifdef LIBXML_OUTPUT_ENABLED
422
/*
423
 * output defaults
424
 */
425
/**
426
 * xmlIndentTreeOutput:
427
 *
428
 * Global setting, asking the serializer to indent the output tree by default
429
 * Enabled by default
430
 */
431
int xmlIndentTreeOutput = 1;
432
static int xmlIndentTreeOutputThrDef = 1;
433
434
/**
435
 * xmlTreeIndentString:
436
 *
437
 * The string used to do one-level indent. By default is equal to "  " (two spaces)
438
 */
439
const char *xmlTreeIndentString = "  ";
440
static const char *xmlTreeIndentStringThrDef = "  ";
441
442
/**
443
 * xmlSaveNoEmptyTags:
444
 *
445
 * Global setting, asking the serializer to not output empty tags
446
 * as <empty/> but <empty></empty>. those two forms are indistinguishable
447
 * once parsed.
448
 * Disabled by default
449
 */
450
int xmlSaveNoEmptyTags = 0;
451
static int xmlSaveNoEmptyTagsThrDef = 0;
452
#endif /* LIBXML_OUTPUT_ENABLED */
453
454
#ifdef LIBXML_SAX1_ENABLED
455
/**
456
 * xmlDefaultSAXHandler:
457
 *
458
 * DEPRECATED: This handler is unused and will be removed from future
459
 * versions.
460
 *
461
 * Default SAX version1 handler for XML, builds the DOM tree
462
 */
463
xmlSAXHandlerV1 xmlDefaultSAXHandler = {
464
    xmlSAX2InternalSubset,
465
    xmlSAX2IsStandalone,
466
    xmlSAX2HasInternalSubset,
467
    xmlSAX2HasExternalSubset,
468
    xmlSAX2ResolveEntity,
469
    xmlSAX2GetEntity,
470
    xmlSAX2EntityDecl,
471
    xmlSAX2NotationDecl,
472
    xmlSAX2AttributeDecl,
473
    xmlSAX2ElementDecl,
474
    xmlSAX2UnparsedEntityDecl,
475
    xmlSAX2SetDocumentLocator,
476
    xmlSAX2StartDocument,
477
    xmlSAX2EndDocument,
478
    xmlSAX2StartElement,
479
    xmlSAX2EndElement,
480
    xmlSAX2Reference,
481
    xmlSAX2Characters,
482
    xmlSAX2Characters,
483
    xmlSAX2ProcessingInstruction,
484
    xmlSAX2Comment,
485
    xmlParserWarning,
486
    xmlParserError,
487
    xmlParserError,
488
    xmlSAX2GetParameterEntity,
489
    xmlSAX2CDataBlock,
490
    xmlSAX2ExternalSubset,
491
    1,
492
};
493
#endif /* LIBXML_SAX1_ENABLED */
494
495
/**
496
 * xmlDefaultSAXLocator:
497
 *
498
 * DEPRECATED: Don't use
499
 *
500
 * The default SAX Locator
501
 * { getPublicId, getSystemId, getLineNumber, getColumnNumber}
502
 */
503
xmlSAXLocator xmlDefaultSAXLocator = {
504
    xmlSAX2GetPublicId,
505
    xmlSAX2GetSystemId,
506
    xmlSAX2GetLineNumber,
507
    xmlSAX2GetColumnNumber
508
};
509
510
#if defined(LIBXML_HTML_ENABLED) && defined(LIBXML_SAX1_ENABLED)
511
/**
512
 * htmlDefaultSAXHandler:
513
 *
514
 * DEPRECATED: This handler is unused and will be removed from future
515
 * versions.
516
 *
517
 * Default old SAX v1 handler for HTML, builds the DOM tree
518
 */
519
xmlSAXHandlerV1 htmlDefaultSAXHandler = {
520
    xmlSAX2InternalSubset,
521
    NULL,
522
    NULL,
523
    NULL,
524
    NULL,
525
    xmlSAX2GetEntity,
526
    NULL,
527
    NULL,
528
    NULL,
529
    NULL,
530
    NULL,
531
    xmlSAX2SetDocumentLocator,
532
    xmlSAX2StartDocument,
533
    xmlSAX2EndDocument,
534
    xmlSAX2StartElement,
535
    xmlSAX2EndElement,
536
    NULL,
537
    xmlSAX2Characters,
538
    xmlSAX2IgnorableWhitespace,
539
    xmlSAX2ProcessingInstruction,
540
    xmlSAX2Comment,
541
    xmlParserWarning,
542
    xmlParserError,
543
    xmlParserError,
544
    NULL,
545
    xmlSAX2CDataBlock,
546
    NULL,
547
    1,
548
};
549
#endif /* LIBXML_HTML_ENABLED */
550
551
/************************************************************************
552
 *                  *
553
 *      Per thread global state handling    *
554
 *                  *
555
 ************************************************************************/
556
557
/**
558
 * xmlInitGlobals:
559
 *
560
 * DEPRECATED: Alias for xmlInitParser.
561
 */
562
0
void xmlInitGlobals(void) {
563
0
    xmlInitParser();
564
0
}
565
566
/**
567
 * xmlInitGlobalsInternal:
568
 *
569
 * Additional initialisation for multi-threading
570
 */
571
11
void xmlInitGlobalsInternal(void) {
572
11
    xmlInitMutex(&xmlThrDefMutex);
573
574
11
#ifdef HAVE_POSIX_THREADS
575
11
#ifdef XML_PTHREAD_WEAK
576
11
    if (libxml_is_threaded == -1)
577
11
        libxml_is_threaded =
578
11
            (pthread_getspecific != NULL) &&
579
11
            (pthread_setspecific != NULL) &&
580
11
            (pthread_key_create != NULL) &&
581
11
            (pthread_key_delete != NULL) &&
582
            /*
583
             * pthread_equal can be inline, resuting in -Waddress warnings.
584
             * Let's assume it's available if all the other functions are.
585
             */
586
            /* (pthread_equal != NULL) && */
587
11
            (pthread_self != NULL);
588
11
    if (libxml_is_threaded == 0)
589
0
        return;
590
11
#endif /* XML_PTHREAD_WEAK */
591
11
    pthread_key_create(&globalkey, xmlFreeGlobalState);
592
11
    mainthread = pthread_self();
593
#elif defined(HAVE_WIN32_THREADS)
594
#ifndef USE_TLS
595
    globalkey = TlsAlloc();
596
#endif
597
    mainthread = GetCurrentThreadId();
598
#endif
599
11
}
600
601
/**
602
 * xmlCleanupGlobals:
603
 *
604
 * DEPRECATED: This function is a no-op. Call xmlCleanupParser
605
 * to free global state but see the warnings there. xmlCleanupParser
606
 * should be only called once at program exit. In most cases, you don't
607
 * have call cleanup functions at all.
608
 */
609
0
void xmlCleanupGlobals(void) {
610
0
}
611
612
/**
613
 * xmlCleanupGlobalsInternal:
614
 *
615
 * Additional cleanup for multi-threading
616
 */
617
0
void xmlCleanupGlobalsInternal(void) {
618
0
    xmlResetError(&xmlLastError);
619
620
0
    xmlCleanupMutex(&xmlThrDefMutex);
621
622
0
#ifdef HAVE_POSIX_THREADS
623
0
#ifdef XML_PTHREAD_WEAK
624
0
    if (libxml_is_threaded == 0)
625
0
        return;
626
0
#endif /* XML_PTHREAD_WEAK */
627
0
    pthread_key_delete(globalkey);
628
#elif defined(HAVE_WIN32_THREADS)
629
#ifndef USE_TLS
630
    if (globalkey != TLS_OUT_OF_INDEXES) {
631
        TlsFree(globalkey);
632
        globalkey = TLS_OUT_OF_INDEXES;
633
    }
634
#endif
635
#endif
636
637
0
    parserInitialized = 0;
638
0
}
639
640
/**
641
 * xmlInitializeGlobalState:
642
 * @gs: a pointer to a newly allocated global state
643
 *
644
 * DEPRECATED: No-op.
645
 */
646
void
647
xmlInitializeGlobalState(xmlGlobalStatePtr gs ATTRIBUTE_UNUSED)
648
0
{
649
0
}
650
651
/**
652
 * xmlGetGlobalState:
653
 *
654
 * DEPRECATED
655
 *
656
 * Returns NULL.
657
 */
658
xmlGlobalStatePtr
659
xmlGetGlobalState(void)
660
0
{
661
0
    return(NULL);
662
0
}
663
664
static int
665
99
xmlIsMainThreadInternal(void) {
666
99
    if (parserInitialized == 0) {
667
11
        xmlInitParser();
668
11
        parserInitialized = 1;
669
11
    }
670
671
99
#ifdef HAVE_POSIX_THREADS
672
99
#ifdef XML_PTHREAD_WEAK
673
99
    if (libxml_is_threaded == 0)
674
0
        return (1);
675
99
#endif
676
99
    return (pthread_equal(mainthread, pthread_self()));
677
#elif defined HAVE_WIN32_THREADS
678
    return (mainthread == GetCurrentThreadId());
679
#else
680
    return (1);
681
#endif
682
99
}
683
684
/**
685
 * xmlIsMainThread:
686
 *
687
 * DEPRECATED: Internal function, do not use.
688
 *
689
 * Check whether the current thread is the main thread.
690
 *
691
 * Returns 1 if the current thread is the main thread, 0 otherwise
692
 */
693
int
694
0
xmlIsMainThread(void) {
695
0
    return(xmlIsMainThreadInternal());
696
0
}
697
698
#ifdef LIBXML_THREAD_ENABLED
699
700
static void
701
xmlFreeGlobalState(void *state)
702
0
{
703
0
    xmlGlobalState *gs = (xmlGlobalState *) state;
704
705
    /*
706
     * Free any memory allocated in the thread's xmlLastError. If it
707
     * weren't for this indirect allocation, we wouldn't need
708
     * a destructor with thread-local storage at all!
709
     *
710
     * It would be nice if we could make xmlLastError a special error
711
     * type which uses statically allocated, fixed-size buffers.
712
     * But the xmlError struct is fully public and widely used,
713
     * so changes are dangerous.
714
     */
715
0
    xmlResetError(&(gs->gs_xmlLastError));
716
#ifndef USE_TLS
717
    free(state);
718
#endif
719
0
}
720
721
#if defined(HAVE_WIN32_THREADS) && \
722
    defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
723
static void WINAPI
724
xmlGlobalStateDtor(void *ctxt, unsigned char timedOut ATTRIBUTE_UNUSED) {
725
    xmlGlobalStatePtr gs = ctxt;
726
727
    UnregisterWait(gs->waitHandle);
728
    CloseHandle(gs->threadHandle);
729
    xmlFreeGlobalState(gs);
730
}
731
732
static int
733
xmlRegisterGlobalStateDtor(xmlGlobalState *gs) {
734
    void *processHandle = GetCurrentProcess();
735
    void *threadHandle;
736
    void *waitHandle;
737
738
    if (DuplicateHandle(processHandle, GetCurrentThread(), processHandle,
739
                &threadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS) == 0) {
740
        return(-1);
741
    }
742
743
    if (RegisterWaitForSingleObject(&waitHandle, threadHandle,
744
                xmlGlobalStateDtor, gs, INFINITE, WT_EXECUTEONLYONCE) == 0) {
745
        CloseHandle(threadHandle);
746
        return(-1);
747
    }
748
749
    gs->threadHandle = threadHandle;
750
    gs->waitHandle = waitHandle;
751
    return(0);
752
}
753
#endif /* LIBXML_STATIC */
754
755
static void
756
0
xmlInitGlobalState(xmlGlobalStatePtr gs) {
757
0
    xmlMutexLock(&xmlThrDefMutex);
758
759
#if defined(LIBXML_HTML_ENABLED) && defined(LIBXML_LEGACY_ENABLED) && defined(LIBXML_SAX1_ENABLED)
760
    inithtmlDefaultSAXHandler(&gs->gs_htmlDefaultSAXHandler);
761
#endif
762
763
0
    gs->gs_oldXMLWDcompatibility = 0;
764
0
    gs->gs_xmlBufferAllocScheme = xmlBufferAllocSchemeThrDef;
765
0
    gs->gs_xmlDefaultBufferSize = xmlDefaultBufferSizeThrDef;
766
#if defined(LIBXML_SAX1_ENABLED) && defined(LIBXML_LEGACY_ENABLED)
767
    initxmlDefaultSAXHandler(&gs->gs_xmlDefaultSAXHandler, 1);
768
#endif /* LIBXML_SAX1_ENABLED */
769
0
    gs->gs_xmlDefaultSAXLocator.getPublicId = xmlSAX2GetPublicId;
770
0
    gs->gs_xmlDefaultSAXLocator.getSystemId = xmlSAX2GetSystemId;
771
0
    gs->gs_xmlDefaultSAXLocator.getLineNumber = xmlSAX2GetLineNumber;
772
0
    gs->gs_xmlDefaultSAXLocator.getColumnNumber = xmlSAX2GetColumnNumber;
773
0
    gs->gs_xmlDoValidityCheckingDefaultValue =
774
0
         xmlDoValidityCheckingDefaultValueThrDef;
775
#ifdef LIBXML_THREAD_ALLOC_ENABLED
776
#ifdef DEBUG_MEMORY_LOCATION
777
    gs->gs_xmlFree = xmlMemFree;
778
    gs->gs_xmlMalloc = xmlMemMalloc;
779
    gs->gs_xmlMallocAtomic = xmlMemMalloc;
780
    gs->gs_xmlRealloc = xmlMemRealloc;
781
    gs->gs_xmlMemStrdup = xmlMemoryStrdup;
782
#else
783
    gs->gs_xmlFree = free;
784
    gs->gs_xmlMalloc = malloc;
785
    gs->gs_xmlMallocAtomic = malloc;
786
    gs->gs_xmlRealloc = realloc;
787
    gs->gs_xmlMemStrdup = xmlPosixStrdup;
788
#endif
789
#endif
790
0
    gs->gs_xmlGetWarningsDefaultValue = xmlGetWarningsDefaultValueThrDef;
791
0
#ifdef LIBXML_OUTPUT_ENABLED
792
0
    gs->gs_xmlIndentTreeOutput = xmlIndentTreeOutputThrDef;
793
0
    gs->gs_xmlTreeIndentString = xmlTreeIndentStringThrDef;
794
0
    gs->gs_xmlSaveNoEmptyTags = xmlSaveNoEmptyTagsThrDef;
795
0
#endif
796
0
    gs->gs_xmlKeepBlanksDefaultValue = xmlKeepBlanksDefaultValueThrDef;
797
0
    gs->gs_xmlLineNumbersDefaultValue = xmlLineNumbersDefaultValueThrDef;
798
0
    gs->gs_xmlLoadExtDtdDefaultValue = xmlLoadExtDtdDefaultValueThrDef;
799
0
    gs->gs_xmlParserDebugEntities = xmlParserDebugEntitiesThrDef;
800
0
    gs->gs_xmlPedanticParserDefaultValue = xmlPedanticParserDefaultValueThrDef;
801
0
    gs->gs_xmlSubstituteEntitiesDefaultValue =
802
0
        xmlSubstituteEntitiesDefaultValueThrDef;
803
804
0
    gs->gs_xmlGenericError = xmlGenericErrorThrDef;
805
0
    gs->gs_xmlStructuredError = xmlStructuredErrorThrDef;
806
0
    gs->gs_xmlGenericErrorContext = xmlGenericErrorContextThrDef;
807
0
    gs->gs_xmlStructuredErrorContext = xmlStructuredErrorContextThrDef;
808
0
    gs->gs_xmlRegisterNodeDefaultValue = xmlRegisterNodeDefaultValueThrDef;
809
0
    gs->gs_xmlDeregisterNodeDefaultValue = xmlDeregisterNodeDefaultValueThrDef;
810
811
0
    gs->gs_xmlParserInputBufferCreateFilenameValue =
812
0
        xmlParserInputBufferCreateFilenameValueThrDef;
813
0
    gs->gs_xmlOutputBufferCreateFilenameValue =
814
0
        xmlOutputBufferCreateFilenameValueThrDef;
815
0
    memset(&gs->gs_xmlLastError, 0, sizeof(xmlError));
816
817
0
    xmlMutexUnlock(&xmlThrDefMutex);
818
819
0
#ifdef HAVE_POSIX_THREADS
820
0
    pthread_setspecific(globalkey, gs);
821
#elif defined HAVE_WIN32_THREADS
822
#ifndef USE_TLS
823
    TlsSetValue(globalkey, gs);
824
#endif
825
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
826
    xmlRegisterGlobalStateDtor(gs);
827
#endif
828
#endif
829
830
0
    gs->initialized = 1;
831
0
}
832
833
#ifndef USE_TLS
834
/**
835
 * xmlNewGlobalState:
836
 *
837
 * xmlNewGlobalState() allocates a global state. This structure is used to
838
 * hold all data for use by a thread when supporting backwards compatibility
839
 * of libxml2 to pre-thread-safe behaviour.
840
 *
841
 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
842
 */
843
static xmlGlobalStatePtr
844
xmlNewGlobalState(int allowFailure)
845
{
846
    xmlGlobalState *gs;
847
848
    gs = malloc(sizeof(xmlGlobalState));
849
    if (gs == NULL) {
850
        if (allowFailure)
851
            return(NULL);
852
853
        /*
854
         * If an application didn't call xmlCheckThreadLocalStorage to make
855
         * sure that global state could be allocated, it's too late to
856
         * handle the error.
857
         */
858
        fprintf(stderr, "libxml2: Failed to allocate globals for thread\n"
859
                        "libxml2: See xmlCheckThreadLocalStorage\n");
860
        abort();
861
    }
862
863
    memset(gs, 0, sizeof(xmlGlobalState));
864
    xmlInitGlobalState(gs);
865
    return (gs);
866
}
867
#endif
868
869
static xmlGlobalStatePtr
870
0
xmlGetThreadLocalStorage(int allowFailure) {
871
0
    xmlGlobalState *gs;
872
873
0
    (void) allowFailure;
874
875
0
#ifdef USE_TLS
876
0
    gs = &globalState;
877
0
    if (gs->initialized == 0)
878
0
        xmlInitGlobalState(gs);
879
#elif defined(HAVE_POSIX_THREADS)
880
    gs = (xmlGlobalState *) pthread_getspecific(globalkey);
881
    if (gs == NULL)
882
        gs = xmlNewGlobalState(allowFailure);
883
#elif defined(HAVE_WIN32_THREADS)
884
    gs = (xmlGlobalState *) TlsGetValue(globalkey);
885
    if (gs == NULL)
886
        gs = xmlNewGlobalState(allowFailure);
887
#else
888
    gs = NULL;
889
#endif
890
891
0
    return(gs);
892
0
}
893
894
/* Define thread-local storage accessors with macro magic */
895
896
#define XML_DEFINE_GLOBAL_WRAPPER(name, type, attrs) \
897
99
    type *__##name(void) { \
898
99
        if (IS_MAIN_THREAD) \
899
99
            return (&name); \
900
99
        else \
901
99
            return (&xmlGetThreadLocalStorage(0)->gs_##name); \
902
99
    }
Unexecuted instantiation: __xmlLastError
Unexecuted instantiation: __xmlGenericError
Unexecuted instantiation: __xmlGenericErrorContext
Unexecuted instantiation: __xmlStructuredError
Unexecuted instantiation: __xmlStructuredErrorContext
Unexecuted instantiation: __htmlDefaultSAXHandler
Unexecuted instantiation: __xmlParserInputBufferCreateFilenameValue
Unexecuted instantiation: __xmlOutputBufferCreateFilenameValue
Unexecuted instantiation: __oldXMLWDcompatibility
Unexecuted instantiation: __xmlDefaultSAXLocator
__xmlDoValidityCheckingDefaultValue
Line
Count
Source
897
11
    type *__##name(void) { \
898
11
        if (IS_MAIN_THREAD) \
899
11
            return (&name); \
900
11
        else \
901
11
            return (&xmlGetThreadLocalStorage(0)->gs_##name); \
902
11
    }
Unexecuted instantiation: __xmlGetWarningsDefaultValue
__xmlKeepBlanksDefaultValue
Line
Count
Source
897
11
    type *__##name(void) { \
898
11
        if (IS_MAIN_THREAD) \
899
11
            return (&name); \
900
11
        else \
901
11
            return (&xmlGetThreadLocalStorage(0)->gs_##name); \
902
11
    }
__xmlLineNumbersDefaultValue
Line
Count
Source
897
11
    type *__##name(void) { \
898
11
        if (IS_MAIN_THREAD) \
899
11
            return (&name); \
900
11
        else \
901
11
            return (&xmlGetThreadLocalStorage(0)->gs_##name); \
902
11
    }
__xmlLoadExtDtdDefaultValue
Line
Count
Source
897
11
    type *__##name(void) { \
898
11
        if (IS_MAIN_THREAD) \
899
11
            return (&name); \
900
11
        else \
901
11
            return (&xmlGetThreadLocalStorage(0)->gs_##name); \
902
11
    }
Unexecuted instantiation: __xmlParserDebugEntities
__xmlPedanticParserDefaultValue
Line
Count
Source
897
11
    type *__##name(void) { \
898
11
        if (IS_MAIN_THREAD) \
899
11
            return (&name); \
900
11
        else \
901
11
            return (&xmlGetThreadLocalStorage(0)->gs_##name); \
902
11
    }
__xmlSubstituteEntitiesDefaultValue
Line
Count
Source
897
11
    type *__##name(void) { \
898
11
        if (IS_MAIN_THREAD) \
899
11
            return (&name); \
900
11
        else \
901
11
            return (&xmlGetThreadLocalStorage(0)->gs_##name); \
902
11
    }
Unexecuted instantiation: __xmlIndentTreeOutput
Unexecuted instantiation: __xmlTreeIndentString
Unexecuted instantiation: __xmlSaveNoEmptyTags
__xmlDefaultSAXHandler
Line
Count
Source
897
11
    type *__##name(void) { \
898
11
        if (IS_MAIN_THREAD) \
899
11
            return (&name); \
900
11
        else \
901
11
            return (&xmlGetThreadLocalStorage(0)->gs_##name); \
902
11
    }
__xmlBufferAllocScheme
Line
Count
Source
897
11
    type *__##name(void) { \
898
11
        if (IS_MAIN_THREAD) \
899
11
            return (&name); \
900
11
        else \
901
11
            return (&xmlGetThreadLocalStorage(0)->gs_##name); \
902
11
    }
__xmlDefaultBufferSize
Line
Count
Source
897
11
    type *__##name(void) { \
898
11
        if (IS_MAIN_THREAD) \
899
11
            return (&name); \
900
11
        else \
901
11
            return (&xmlGetThreadLocalStorage(0)->gs_##name); \
902
11
    }
Unexecuted instantiation: __xmlRegisterNodeDefaultValue
Unexecuted instantiation: __xmlDeregisterNodeDefaultValue
903
904
#define XML_OP XML_DEFINE_GLOBAL_WRAPPER
905
XML_GLOBALS_ALLOC
906
XML_GLOBALS_ERROR
907
XML_GLOBALS_HTML
908
XML_GLOBALS_IO
909
XML_GLOBALS_PARSER
910
XML_GLOBALS_TREE
911
#undef XML_OP
912
913
/* For backward compatibility */
914
915
const char *const *
916
0
__xmlParserVersion(void) {
917
0
    return &xmlParserVersion;
918
0
}
919
920
#endif /* LIBXML_THREAD_ENABLED */
921
922
/**
923
 * xmlCheckThreadLocalStorage:
924
 *
925
 * Check whether thread-local storage could be allocated.
926
 *
927
 * In cross-platform code running in multithreaded environments, this
928
 * function should be called once in each thread before calling other
929
 * library functions to make sure that thread-local storage was
930
 * allocated properly.
931
 *
932
 * Returns 0 on success or -1 if a memory allocation failed. A failed
933
 * allocation signals a typically fatal and irrecoverable out-of-memory
934
 * situation. Don't call any library functions in this case.
935
 *
936
 * This function never fails if the library is compiled with support
937
 * for thread-local storage.
938
 *
939
 * This function never fails for the "main" thread which is the first
940
 * thread calling xmlInitParser.
941
 *
942
 * Available since v2.12.0.
943
 */
944
int
945
0
xmlCheckThreadLocalStorage(void) {
946
#if defined(LIBXML_THREAD_ENABLED) && !defined(USE_TLS)
947
    if ((!xmlIsMainThreadInternal()) && (xmlGetThreadLocalStorage(1) == NULL))
948
        return(-1);
949
#endif
950
0
    return(0);
951
0
}
952
953
/**
954
 * DllMain:
955
 * @hinstDLL: handle to DLL instance
956
 * @fdwReason: Reason code for entry
957
 * @lpvReserved: generic pointer (depends upon reason code)
958
 *
959
 * Entry point for Windows library. It is being used to free thread-specific
960
 * storage.
961
 *
962
 * Returns TRUE always
963
 */
964
#if defined(HAVE_WIN32_THREADS) && \
965
    (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
966
#if defined(LIBXML_STATIC_FOR_DLL)
967
int
968
xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason,
969
           ATTRIBUTE_UNUSED void *lpvReserved)
970
#else
971
/* declare to avoid "no previous prototype for 'DllMain'" warning */
972
/* Note that we do NOT want to include this function declaration in
973
   a public header because it's meant to be called by Windows itself,
974
   not a program that uses this library.  This also has to be exported. */
975
976
XMLPUBFUN BOOL WINAPI
977
DllMain (HINSTANCE hinstDLL,
978
         DWORD     fdwReason,
979
         LPVOID    lpvReserved);
980
981
BOOL WINAPI
982
DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
983
        ATTRIBUTE_UNUSED LPVOID lpvReserved)
984
#endif
985
{
986
    switch (fdwReason) {
987
        case DLL_THREAD_DETACH:
988
#ifdef USE_TLS
989
            xmlFreeGlobalState(&globalState);
990
#else
991
            if (globalkey != TLS_OUT_OF_INDEXES) {
992
                xmlGlobalState *globalval;
993
994
                globalval = (xmlGlobalState *) TlsGetValue(globalkey);
995
                if (globalval) {
996
                    xmlFreeGlobalState(globalval);
997
                    TlsSetValue(globalkey, NULL);
998
                }
999
            }
1000
#endif
1001
            break;
1002
    }
1003
    return TRUE;
1004
}
1005
#endif
1006
1007
void
1008
0
xmlThrDefSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
1009
0
    xmlMutexLock(&xmlThrDefMutex);
1010
0
    xmlGenericErrorContextThrDef = ctx;
1011
0
    if (handler != NULL)
1012
0
  xmlGenericErrorThrDef = handler;
1013
0
    else
1014
0
  xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc;
1015
0
    xmlMutexUnlock(&xmlThrDefMutex);
1016
0
}
1017
1018
void
1019
0
xmlThrDefSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) {
1020
0
    xmlMutexLock(&xmlThrDefMutex);
1021
0
    xmlStructuredErrorContextThrDef = ctx;
1022
0
    xmlStructuredErrorThrDef = handler;
1023
0
    xmlMutexUnlock(&xmlThrDefMutex);
1024
0
}
1025
1026
0
xmlBufferAllocationScheme xmlThrDefBufferAllocScheme(xmlBufferAllocationScheme v) {
1027
0
    xmlBufferAllocationScheme ret;
1028
0
    xmlMutexLock(&xmlThrDefMutex);
1029
0
    ret = xmlBufferAllocSchemeThrDef;
1030
0
    xmlBufferAllocSchemeThrDef = v;
1031
0
    xmlMutexUnlock(&xmlThrDefMutex);
1032
0
    return ret;
1033
0
}
1034
1035
0
int xmlThrDefDefaultBufferSize(int v) {
1036
0
    int ret;
1037
0
    xmlMutexLock(&xmlThrDefMutex);
1038
0
    ret = xmlDefaultBufferSizeThrDef;
1039
0
    xmlDefaultBufferSizeThrDef = v;
1040
0
    xmlMutexUnlock(&xmlThrDefMutex);
1041
0
    return ret;
1042
0
}
1043
1044
0
int xmlThrDefDoValidityCheckingDefaultValue(int v) {
1045
0
    int ret;
1046
0
    xmlMutexLock(&xmlThrDefMutex);
1047
0
    ret = xmlDoValidityCheckingDefaultValueThrDef;
1048
0
    xmlDoValidityCheckingDefaultValueThrDef = v;
1049
0
    xmlMutexUnlock(&xmlThrDefMutex);
1050
0
    return ret;
1051
0
}
1052
1053
0
int xmlThrDefGetWarningsDefaultValue(int v) {
1054
0
    int ret;
1055
0
    xmlMutexLock(&xmlThrDefMutex);
1056
0
    ret = xmlGetWarningsDefaultValueThrDef;
1057
0
    xmlGetWarningsDefaultValueThrDef = v;
1058
0
    xmlMutexUnlock(&xmlThrDefMutex);
1059
0
    return ret;
1060
0
}
1061
1062
#ifdef LIBXML_OUTPUT_ENABLED
1063
0
int xmlThrDefIndentTreeOutput(int v) {
1064
0
    int ret;
1065
0
    xmlMutexLock(&xmlThrDefMutex);
1066
0
    ret = xmlIndentTreeOutputThrDef;
1067
0
    xmlIndentTreeOutputThrDef = v;
1068
0
    xmlMutexUnlock(&xmlThrDefMutex);
1069
0
    return ret;
1070
0
}
1071
1072
0
const char * xmlThrDefTreeIndentString(const char * v) {
1073
0
    const char * ret;
1074
0
    xmlMutexLock(&xmlThrDefMutex);
1075
0
    ret = xmlTreeIndentStringThrDef;
1076
0
    xmlTreeIndentStringThrDef = v;
1077
0
    xmlMutexUnlock(&xmlThrDefMutex);
1078
0
    return ret;
1079
0
}
1080
1081
0
int xmlThrDefSaveNoEmptyTags(int v) {
1082
0
    int ret;
1083
0
    xmlMutexLock(&xmlThrDefMutex);
1084
0
    ret = xmlSaveNoEmptyTagsThrDef;
1085
0
    xmlSaveNoEmptyTagsThrDef = v;
1086
0
    xmlMutexUnlock(&xmlThrDefMutex);
1087
0
    return ret;
1088
0
}
1089
#endif
1090
1091
0
int xmlThrDefKeepBlanksDefaultValue(int v) {
1092
0
    int ret;
1093
0
    xmlMutexLock(&xmlThrDefMutex);
1094
0
    ret = xmlKeepBlanksDefaultValueThrDef;
1095
0
    xmlKeepBlanksDefaultValueThrDef = v;
1096
0
    xmlMutexUnlock(&xmlThrDefMutex);
1097
0
    return ret;
1098
0
}
1099
1100
0
int xmlThrDefLineNumbersDefaultValue(int v) {
1101
0
    int ret;
1102
0
    xmlMutexLock(&xmlThrDefMutex);
1103
0
    ret = xmlLineNumbersDefaultValueThrDef;
1104
0
    xmlLineNumbersDefaultValueThrDef = v;
1105
0
    xmlMutexUnlock(&xmlThrDefMutex);
1106
0
    return ret;
1107
0
}
1108
1109
0
int xmlThrDefLoadExtDtdDefaultValue(int v) {
1110
0
    int ret;
1111
0
    xmlMutexLock(&xmlThrDefMutex);
1112
0
    ret = xmlLoadExtDtdDefaultValueThrDef;
1113
0
    xmlLoadExtDtdDefaultValueThrDef = v;
1114
0
    xmlMutexUnlock(&xmlThrDefMutex);
1115
0
    return ret;
1116
0
}
1117
1118
0
int xmlThrDefParserDebugEntities(int v) {
1119
0
    int ret;
1120
0
    xmlMutexLock(&xmlThrDefMutex);
1121
0
    ret = xmlParserDebugEntitiesThrDef;
1122
0
    xmlParserDebugEntitiesThrDef = v;
1123
0
    xmlMutexUnlock(&xmlThrDefMutex);
1124
0
    return ret;
1125
0
}
1126
1127
0
int xmlThrDefPedanticParserDefaultValue(int v) {
1128
0
    int ret;
1129
0
    xmlMutexLock(&xmlThrDefMutex);
1130
0
    ret = xmlPedanticParserDefaultValueThrDef;
1131
0
    xmlPedanticParserDefaultValueThrDef = v;
1132
0
    xmlMutexUnlock(&xmlThrDefMutex);
1133
0
    return ret;
1134
0
}
1135
1136
0
int xmlThrDefSubstituteEntitiesDefaultValue(int v) {
1137
0
    int ret;
1138
0
    xmlMutexLock(&xmlThrDefMutex);
1139
0
    ret = xmlSubstituteEntitiesDefaultValueThrDef;
1140
0
    xmlSubstituteEntitiesDefaultValueThrDef = v;
1141
0
    xmlMutexUnlock(&xmlThrDefMutex);
1142
0
    return ret;
1143
0
}
1144
1145
xmlRegisterNodeFunc
1146
xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func)
1147
0
{
1148
0
    xmlRegisterNodeFunc old;
1149
1150
0
    xmlMutexLock(&xmlThrDefMutex);
1151
0
    old = xmlRegisterNodeDefaultValueThrDef;
1152
1153
0
    __xmlRegisterCallbacks = 1;
1154
0
    xmlRegisterNodeDefaultValueThrDef = func;
1155
0
    xmlMutexUnlock(&xmlThrDefMutex);
1156
1157
0
    return(old);
1158
0
}
1159
1160
xmlDeregisterNodeFunc
1161
xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func)
1162
0
{
1163
0
    xmlDeregisterNodeFunc old;
1164
1165
0
    xmlMutexLock(&xmlThrDefMutex);
1166
0
    old = xmlDeregisterNodeDefaultValueThrDef;
1167
1168
0
    __xmlRegisterCallbacks = 1;
1169
0
    xmlDeregisterNodeDefaultValueThrDef = func;
1170
0
    xmlMutexUnlock(&xmlThrDefMutex);
1171
1172
0
    return(old);
1173
0
}
1174
1175
xmlParserInputBufferCreateFilenameFunc
1176
xmlThrDefParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
1177
0
{
1178
0
    xmlParserInputBufferCreateFilenameFunc old;
1179
1180
0
    xmlMutexLock(&xmlThrDefMutex);
1181
0
    old = xmlParserInputBufferCreateFilenameValueThrDef;
1182
0
    if (old == NULL) {
1183
0
    old = __xmlParserInputBufferCreateFilename;
1184
0
  }
1185
1186
0
    xmlParserInputBufferCreateFilenameValueThrDef = func;
1187
0
    xmlMutexUnlock(&xmlThrDefMutex);
1188
1189
0
    return(old);
1190
0
}
1191
1192
xmlOutputBufferCreateFilenameFunc
1193
xmlThrDefOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
1194
0
{
1195
0
    xmlOutputBufferCreateFilenameFunc old;
1196
1197
0
    xmlMutexLock(&xmlThrDefMutex);
1198
0
    old = xmlOutputBufferCreateFilenameValueThrDef;
1199
0
#ifdef LIBXML_OUTPUT_ENABLED
1200
0
    if (old == NULL) {
1201
0
    old = __xmlOutputBufferCreateFilename;
1202
0
  }
1203
0
#endif
1204
0
    xmlOutputBufferCreateFilenameValueThrDef = func;
1205
0
    xmlMutexUnlock(&xmlThrDefMutex);
1206
1207
0
    return(old);
1208
0
}
1209