Coverage Report

Created: 2026-05-23 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libxml2/globals.c
Line
Count
Source
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
8
#define IN_LIBXML
9
#include "libxml.h"
10
11
#include <stdlib.h>
12
#include <string.h>
13
14
#define XML_GLOBALS_NO_REDEFINITION
15
#include <libxml/xmlerror.h>
16
#include <libxml/xmlmemory.h>
17
#include <libxml/xmlIO.h>
18
#include <libxml/HTMLparser.h>
19
#include <libxml/parser.h>
20
#include <libxml/threads.h>
21
#include <libxml/tree.h>
22
#include <libxml/xmlsave.h>
23
#include <libxml/SAX2.h>
24
25
#include "private/dict.h"
26
#include "private/error.h"
27
#include "private/globals.h"
28
#include "private/threads.h"
29
#include "private/tree.h"
30
31
/*
32
 * Mutex to protect "ForNewThreads" variables
33
 */
34
static xmlMutex xmlThrDefMutex;
35
36
/*
37
 * Deprecated global setting which is unused since 2.15.0
38
 */
39
static int lineNumbersDefaultValue = 1;
40
41
/*
42
 * Thread-local storage emulation.
43
 *
44
 * This works by replacing a global variable
45
 *
46
 *     extern xmlError xmlLastError;
47
 *
48
 * with a macro that calls a function returning a pointer to the global in
49
 * thread-local storage:
50
 *
51
 *     xmlError *__xmlLastError(void);
52
 *     #define xmlError (*__xmlLastError());
53
 *
54
 * The code can operate in a multitude of ways depending on the environment.
55
 * First we support POSIX and Windows threads. Then we support both
56
 * thread-local storage provided by the compiler and older methods like
57
 * thread-specific data (pthreads) or TlsAlloc (Windows).
58
 *
59
 * To clean up thread-local storage, we use thread-specific data on POSIX.
60
 * On Windows, we either use DllMain when compiling a DLL or a registered
61
 * wait function for static builds.
62
 *
63
 * Compiler TLS isn't really useful for now. It can make allocation more
64
 * robust on some platforms but it also increases the memory consumption
65
 * of each thread by ~250 bytes whether it uses libxml2 or not. The main
66
 * problem is that we have to deallocate strings in xmlLastError and C
67
 * offers no simple way to deallocate dynamic data in _Thread_local
68
 * variables. In C++, one could simply use a thread_local variable with a
69
 * destructor.
70
 *
71
 * At some point, many of the deprecated globals can be removed,
72
 * although things like global error handlers will take a while.
73
 * Ultimately, the only crucial things seem to be xmlLastError and
74
 * RNG state. xmlLastError already involves dynamic allocation, so it
75
 * could be allocated dynamically as well, only storing a global
76
 * pointer.
77
 */
78
79
#ifdef LIBXML_THREAD_ENABLED
80
81
#ifdef HAVE_WIN32_THREADS
82
  #if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
83
    #define USE_WAIT_DTOR
84
  #else
85
    #define USE_DLL_MAIN
86
  #endif
87
#endif
88
89
/*
90
 * On Darwin, thread-local storage destructors seem to be run before
91
 * pthread thread-specific data destructors. This causes ASan to
92
 * report a use-after-free.
93
 *
94
 * On Windows, we can't use TLS in static builds. The RegisterWait
95
 * callback would run after TLS was deallocated.
96
 */
97
#if defined(XML_THREAD_LOCAL) && \
98
    !defined(__APPLE__) && \
99
    !defined(USE_WAIT_DTOR)
100
#define USE_TLS
101
#endif
102
103
#ifdef HAVE_POSIX_THREADS
104
105
/*
106
 * On POSIX, we need thread-specific data even with thread-local storage
107
 * to destroy indirect references from global state (xmlLastError) at
108
 * thread exit.
109
 */
110
static pthread_key_t globalkey;
111
112
#elif defined HAVE_WIN32_THREADS
113
114
#ifndef USE_TLS
115
static DWORD globalkey = TLS_OUT_OF_INDEXES;
116
#endif
117
118
#endif /* HAVE_WIN32_THREADS */
119
120
static void
121
xmlFreeGlobalState(void *state);
122
123
#endif /* LIBXML_THREAD_ENABLED */
124
125
struct _xmlGlobalState {
126
#ifdef USE_TLS
127
    int initialized;
128
#endif
129
130
#ifdef USE_WAIT_DTOR
131
    void *threadHandle;
132
    void *waitHandle;
133
#endif
134
135
    unsigned localRngState[2];
136
137
    xmlError lastError;
138
139
#ifdef LIBXML_THREAD_ALLOC_ENABLED
140
    xmlMallocFunc malloc;
141
    xmlMallocFunc mallocAtomic;
142
    xmlReallocFunc realloc;
143
    xmlFreeFunc free;
144
    xmlStrdupFunc memStrdup;
145
#endif
146
147
    int doValidityCheckingDefaultValue;
148
    int getWarningsDefaultValue;
149
    int keepBlanksDefaultValue;
150
    int loadExtDtdDefaultValue;
151
    int pedanticParserDefaultValue;
152
    int substituteEntitiesDefaultValue;
153
154
#ifdef LIBXML_OUTPUT_ENABLED
155
    int indentTreeOutput;
156
    const char *treeIndentString;
157
    int saveNoEmptyTags;
158
#endif
159
160
    xmlGenericErrorFunc genericError;
161
    void *genericErrorContext;
162
    xmlStructuredErrorFunc structuredError;
163
    void *structuredErrorContext;
164
165
    xmlRegisterNodeFunc registerNodeDefaultValue;
166
    xmlDeregisterNodeFunc deregisterNodeDefaultValue;
167
168
    xmlParserInputBufferCreateFilenameFunc parserInputBufferCreateFilenameValue;
169
    xmlOutputBufferCreateFilenameFunc outputBufferCreateFilenameValue;
170
};
171
172
typedef struct _xmlGlobalState xmlGlobalState;
173
typedef xmlGlobalState *xmlGlobalStatePtr;
174
175
#ifdef LIBXML_THREAD_ENABLED
176
177
#ifdef USE_TLS
178
static XML_THREAD_LOCAL xmlGlobalState globalState;
179
#endif
180
181
#else /* LIBXML_THREAD_ENABLED */
182
183
static xmlGlobalState globalState;
184
185
#endif /* LIBXML_THREAD_ENABLED */
186
187
/************************************************************************
188
 *                  *
189
 *  All the user accessible global variables of the library   *
190
 *                  *
191
 ************************************************************************/
192
193
/**
194
 * a strdup implementation with a type signature matching POSIX
195
 *
196
 * @param cur  the input char *
197
 * @returns a new xmlChar * or NULL
198
 */
199
static char *
200
38.8k
xmlPosixStrdup(const char *cur) {
201
38.8k
    return((char*) xmlCharStrdup(cur));
202
38.8k
}
203
204
/*
205
 * Memory allocation routines
206
 */
207
208
xmlFreeFunc xmlFree = free;
209
xmlMallocFunc xmlMalloc = malloc;
210
xmlMallocFunc xmlMallocAtomic = malloc;
211
xmlReallocFunc xmlRealloc = realloc;
212
xmlStrdupFunc xmlMemStrdup = xmlPosixStrdup;
213
214
/*
215
 * Parser defaults
216
 */
217
218
static int xmlDoValidityCheckingDefaultValueThrDef = 0;
219
static int xmlGetWarningsDefaultValueThrDef = 1;
220
static int xmlLoadExtDtdDefaultValueThrDef = 0;
221
static int xmlPedanticParserDefaultValueThrDef = 0;
222
static int xmlKeepBlanksDefaultValueThrDef = 1;
223
static int xmlSubstituteEntitiesDefaultValueThrDef = 0;
224
225
static xmlRegisterNodeFunc xmlRegisterNodeDefaultValueThrDef = NULL;
226
static xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValueThrDef = NULL;
227
228
static xmlParserInputBufferCreateFilenameFunc
229
xmlParserInputBufferCreateFilenameValueThrDef = NULL;
230
static xmlOutputBufferCreateFilenameFunc
231
xmlOutputBufferCreateFilenameValueThrDef = NULL;
232
233
static xmlGenericErrorFunc xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc;
234
static xmlStructuredErrorFunc xmlStructuredErrorThrDef = NULL;
235
static void *xmlGenericErrorContextThrDef = NULL;
236
static void *xmlStructuredErrorContextThrDef = NULL;
237
238
#ifdef LIBXML_OUTPUT_ENABLED
239
static int xmlIndentTreeOutputThrDef = 1;
240
static const char *xmlTreeIndentStringThrDef = "  ";
241
static int xmlSaveNoEmptyTagsThrDef = 0;
242
#endif /* LIBXML_OUTPUT_ENABLED */
243
244
#ifdef LIBXML_SAX1_ENABLED
245
/**
246
 * Default SAX version1 handler for XML, builds the DOM tree
247
 *
248
 * @deprecated This handler is unused and will be removed from future
249
 * versions.
250
 *
251
 */
252
const xmlSAXHandlerV1 xmlDefaultSAXHandler = {
253
    xmlSAX2InternalSubset,
254
    xmlSAX2IsStandalone,
255
    xmlSAX2HasInternalSubset,
256
    xmlSAX2HasExternalSubset,
257
    xmlSAX2ResolveEntity,
258
    xmlSAX2GetEntity,
259
    xmlSAX2EntityDecl,
260
    xmlSAX2NotationDecl,
261
    xmlSAX2AttributeDecl,
262
    xmlSAX2ElementDecl,
263
    xmlSAX2UnparsedEntityDecl,
264
    xmlSAX2SetDocumentLocator,
265
    xmlSAX2StartDocument,
266
    xmlSAX2EndDocument,
267
    xmlSAX2StartElement,
268
    xmlSAX2EndElement,
269
    xmlSAX2Reference,
270
    xmlSAX2Characters,
271
    xmlSAX2Characters,
272
    xmlSAX2ProcessingInstruction,
273
    xmlSAX2Comment,
274
    xmlParserWarning,
275
    xmlParserError,
276
    xmlParserError,
277
    xmlSAX2GetParameterEntity,
278
    xmlSAX2CDataBlock,
279
    xmlSAX2ExternalSubset,
280
    1,
281
};
282
#endif /* LIBXML_SAX1_ENABLED */
283
284
/**
285
 * The default SAX Locator
286
 * { getPublicId, getSystemId, getLineNumber, getColumnNumber}
287
 *
288
 * @deprecated Don't use
289
 *
290
 */
291
const xmlSAXLocator xmlDefaultSAXLocator = {
292
    xmlSAX2GetPublicId,
293
    xmlSAX2GetSystemId,
294
    xmlSAX2GetLineNumber,
295
    xmlSAX2GetColumnNumber
296
};
297
298
#if defined(LIBXML_HTML_ENABLED) && defined(LIBXML_SAX1_ENABLED)
299
/**
300
 * Default old SAX v1 handler for HTML, builds the DOM tree
301
 *
302
 * @deprecated This handler is unused and will be removed from future
303
 * versions.
304
 *
305
 */
306
const xmlSAXHandlerV1 htmlDefaultSAXHandler = {
307
    xmlSAX2InternalSubset,
308
    NULL,
309
    NULL,
310
    NULL,
311
    NULL,
312
    xmlSAX2GetEntity,
313
    NULL,
314
    NULL,
315
    NULL,
316
    NULL,
317
    NULL,
318
    xmlSAX2SetDocumentLocator,
319
    xmlSAX2StartDocument,
320
    xmlSAX2EndDocument,
321
    xmlSAX2StartElement,
322
    xmlSAX2EndElement,
323
    NULL,
324
    xmlSAX2Characters,
325
    xmlSAX2IgnorableWhitespace,
326
    xmlSAX2ProcessingInstruction,
327
    xmlSAX2Comment,
328
    xmlParserWarning,
329
    xmlParserError,
330
    xmlParserError,
331
    NULL,
332
    xmlSAX2CDataBlock,
333
    NULL,
334
    1,
335
};
336
#endif /* LIBXML_HTML_ENABLED */
337
338
static void
339
xmlInitGlobalState(xmlGlobalStatePtr gs);
340
341
/************************************************************************
342
 *                  *
343
 *      Per thread global state handling    *
344
 *                  *
345
 ************************************************************************/
346
347
/**
348
 * @deprecated Alias for #xmlInitParser.
349
 */
350
0
void xmlInitGlobals(void) {
351
0
    xmlInitParser();
352
0
}
353
354
/**
355
 * Additional initialisation for multi-threading
356
 */
357
17.0k
void xmlInitGlobalsInternal(void) {
358
17.0k
    xmlInitMutex(&xmlThrDefMutex);
359
360
17.0k
#ifdef HAVE_POSIX_THREADS
361
17.0k
    pthread_key_create(&globalkey, xmlFreeGlobalState);
362
#elif defined(HAVE_WIN32_THREADS)
363
#ifndef USE_TLS
364
    if (globalkey == TLS_OUT_OF_INDEXES)
365
        globalkey = TlsAlloc();
366
#endif
367
#else /* no thread support */
368
    xmlInitGlobalState(&globalState);
369
#endif
370
17.0k
}
371
372
/**
373
 * @deprecated This function is a no-op. Call #xmlCleanupParser
374
 * to free global state but see the warnings there. #xmlCleanupParser
375
 * should be only called once at program exit. In most cases, you don't
376
 * have call cleanup functions at all.
377
 */
378
0
void xmlCleanupGlobals(void) {
379
0
}
380
381
/**
382
 * Additional cleanup for multi-threading
383
 */
384
17.0k
void xmlCleanupGlobalsInternal(void) {
385
    /*
386
     * We assume that all other threads using the library have
387
     * terminated and the last remaining thread calls
388
     * xmlCleanupParser.
389
     */
390
391
17.0k
#ifdef HAVE_POSIX_THREADS
392
    /*
393
     * Free thread-specific data of last thread before calling
394
     * pthread_key_delete.
395
     */
396
17.0k
    xmlGlobalState *gs = pthread_getspecific(globalkey);
397
17.0k
    if (gs != NULL)
398
17.0k
        xmlFreeGlobalState(gs);
399
17.0k
    pthread_key_delete(globalkey);
400
#elif defined(HAVE_WIN32_THREADS)
401
#if defined(USE_WAIT_DTOR) && !defined(USE_TLS)
402
    if (globalkey != TLS_OUT_OF_INDEXES) {
403
        xmlGlobalState* gs = (xmlGlobalState*)TlsGetValue(globalkey);
404
        if (gs) {
405
            /* Unregister the waiter for the thread to terminate, then go ahead
406
               and free the global state. This avoids false positive reports of
407
               memory leaks in applications where the main thread created the
408
               global state; if the registered callback is waiting for the main
409
               thread to terminate to free the global state, it won't get a
410
               chance to run.
411
            */
412
            if (gs->waitHandle != NULL) {
413
                UnregisterWait(gs->waitHandle);
414
                gs->waitHandle = NULL;
415
            }
416
           
417
            if (gs->threadHandle != NULL) {
418
                CloseHandle(gs->threadHandle);
419
                gs->threadHandle = NULL;
420
            }
421
            
422
            xmlFreeGlobalState(gs);
423
            TlsSetValue(globalkey, NULL);
424
        }
425
        TlsFree(globalkey);
426
        globalkey = TLS_OUT_OF_INDEXES;
427
    }
428
#endif
429
#else /* no thread support */
430
    xmlResetError(&globalState.lastError);
431
#endif
432
433
17.0k
    xmlCleanupMutex(&xmlThrDefMutex);
434
17.0k
}
435
436
#ifdef LIBXML_THREAD_ENABLED
437
438
static void
439
xmlFreeGlobalState(void *state)
440
17.0k
{
441
17.0k
    xmlGlobalState *gs = (xmlGlobalState *) state;
442
443
    /*
444
     * Free any memory allocated in the thread's error struct. If it
445
     * weren't for this indirect allocation, we wouldn't need
446
     * a destructor with thread-local storage at all!
447
     */
448
17.0k
    xmlResetError(&gs->lastError);
449
17.0k
#ifndef USE_TLS
450
17.0k
    free(state);
451
17.0k
#endif
452
17.0k
}
453
454
#if defined(USE_WAIT_DTOR)
455
static void WINAPI
456
xmlGlobalStateDtor(void *ctxt, unsigned char timedOut ATTRIBUTE_UNUSED) {
457
    xmlGlobalStatePtr gs = ctxt;
458
459
    UnregisterWait(gs->waitHandle);
460
    CloseHandle(gs->threadHandle);
461
    xmlFreeGlobalState(gs);
462
}
463
464
static int
465
xmlRegisterGlobalStateDtor(xmlGlobalState *gs) {
466
    void *processHandle = GetCurrentProcess();
467
    void *threadHandle;
468
    void *waitHandle;
469
470
    if (DuplicateHandle(processHandle, GetCurrentThread(), processHandle,
471
                &threadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS) == 0) {
472
        return(-1);
473
    }
474
475
    if (RegisterWaitForSingleObject(&waitHandle, threadHandle,
476
                xmlGlobalStateDtor, gs, INFINITE, WT_EXECUTEONLYONCE) == 0) {
477
        CloseHandle(threadHandle);
478
        return(-1);
479
    }
480
481
    gs->threadHandle = threadHandle;
482
    gs->waitHandle = waitHandle;
483
    return(0);
484
}
485
#endif /* USE_WAIT_DTOR */
486
487
#ifndef USE_TLS
488
/**
489
 * Allocates a global state. This structure is used to
490
 * hold all data for use by a thread when supporting backwards compatibility
491
 * of libxml2 to pre-thread-safe behaviour.
492
 *
493
 * @returns the newly allocated xmlGlobalState or NULL in case of error
494
 */
495
static xmlGlobalStatePtr
496
xmlNewGlobalState(int allowFailure)
497
17.0k
{
498
17.0k
    xmlGlobalState *gs;
499
500
    /*
501
     * We use malloc/free to allow accessing globals before setting
502
     * custom memory allocators.
503
     */
504
17.0k
    gs = malloc(sizeof(xmlGlobalState));
505
17.0k
    if (gs == NULL) {
506
0
        if (allowFailure)
507
0
            return(NULL);
508
509
        /*
510
         * If an application didn't call xmlCheckThreadLocalStorage to make
511
         * sure that global state could be allocated, it's too late to
512
         * handle the error.
513
         */
514
0
        xmlAbort("libxml2: Failed to allocate globals for thread\n"
515
0
                 "libxml2: See xmlCheckThreadLocalStorage\n");
516
0
    }
517
518
17.0k
    memset(gs, 0, sizeof(xmlGlobalState));
519
17.0k
    xmlInitGlobalState(gs);
520
17.0k
    return (gs);
521
17.0k
}
522
#endif
523
524
static xmlGlobalStatePtr
525
17.5M
xmlGetThreadLocalStorage(int allowFailure) {
526
17.5M
    xmlGlobalState *gs;
527
528
17.5M
    (void) allowFailure;
529
530
17.5M
    xmlInitParser();
531
532
#ifdef USE_TLS
533
    gs = &globalState;
534
    if (gs->initialized == 0)
535
        xmlInitGlobalState(gs);
536
#elif defined(HAVE_POSIX_THREADS)
537
    gs = (xmlGlobalState *) pthread_getspecific(globalkey);
538
17.5M
    if (gs == NULL)
539
17.0k
        gs = xmlNewGlobalState(allowFailure);
540
#elif defined(HAVE_WIN32_THREADS)
541
    gs = (xmlGlobalState *) TlsGetValue(globalkey);
542
    if (gs == NULL)
543
        gs = xmlNewGlobalState(allowFailure);
544
#else
545
    gs = NULL;
546
#endif
547
548
17.5M
    return(gs);
549
17.5M
}
550
551
#else /* LIBXML_THREAD_ENABLED */
552
553
static xmlGlobalStatePtr
554
xmlGetThreadLocalStorage(int allowFailure ATTRIBUTE_UNUSED) {
555
    return(&globalState);
556
}
557
558
#endif /* LIBXML_THREAD_ENABLED */
559
560
static void
561
17.0k
xmlInitGlobalState(xmlGlobalStatePtr gs) {
562
17.0k
    gs->localRngState[0] = xmlGlobalRandom();
563
17.0k
    gs->localRngState[1] = xmlGlobalRandom();
564
565
17.0k
    memset(&gs->lastError, 0, sizeof(xmlError));
566
567
#ifdef LIBXML_THREAD_ALLOC_ENABLED
568
    /* XML_GLOBALS_ALLOC */
569
    gs->free = free;
570
    gs->malloc = malloc;
571
    gs->mallocAtomic = malloc;
572
    gs->realloc = realloc;
573
    gs->memStrdup = xmlPosixStrdup;
574
#endif
575
576
17.0k
    xmlMutexLock(&xmlThrDefMutex);
577
578
    /* XML_GLOBALS_PARSER */
579
17.0k
    gs->doValidityCheckingDefaultValue =
580
17.0k
         xmlDoValidityCheckingDefaultValueThrDef;
581
17.0k
    gs->getWarningsDefaultValue = xmlGetWarningsDefaultValueThrDef;
582
17.0k
    gs->keepBlanksDefaultValue = xmlKeepBlanksDefaultValueThrDef;
583
17.0k
    gs->loadExtDtdDefaultValue = xmlLoadExtDtdDefaultValueThrDef;
584
17.0k
    gs->pedanticParserDefaultValue = xmlPedanticParserDefaultValueThrDef;
585
17.0k
    gs->substituteEntitiesDefaultValue =
586
17.0k
        xmlSubstituteEntitiesDefaultValueThrDef;
587
17.0k
#ifdef LIBXML_OUTPUT_ENABLED
588
17.0k
    gs->indentTreeOutput = xmlIndentTreeOutputThrDef;
589
17.0k
    gs->treeIndentString = xmlTreeIndentStringThrDef;
590
17.0k
    gs->saveNoEmptyTags = xmlSaveNoEmptyTagsThrDef;
591
17.0k
#endif
592
593
    /* XML_GLOBALS_ERROR */
594
17.0k
    gs->genericError = xmlGenericErrorThrDef;
595
17.0k
    gs->structuredError = xmlStructuredErrorThrDef;
596
17.0k
    gs->genericErrorContext = xmlGenericErrorContextThrDef;
597
17.0k
    gs->structuredErrorContext = xmlStructuredErrorContextThrDef;
598
599
    /* XML_GLOBALS_TREE */
600
17.0k
    gs->registerNodeDefaultValue = xmlRegisterNodeDefaultValueThrDef;
601
17.0k
    gs->deregisterNodeDefaultValue = xmlDeregisterNodeDefaultValueThrDef;
602
603
    /* XML_GLOBALS_IO */
604
17.0k
    gs->parserInputBufferCreateFilenameValue =
605
17.0k
        xmlParserInputBufferCreateFilenameValueThrDef;
606
17.0k
    gs->outputBufferCreateFilenameValue =
607
17.0k
        xmlOutputBufferCreateFilenameValueThrDef;
608
609
17.0k
    xmlMutexUnlock(&xmlThrDefMutex);
610
611
#ifdef USE_TLS
612
    gs->initialized = 1;
613
#endif
614
615
17.0k
#ifdef HAVE_POSIX_THREADS
616
17.0k
    pthread_setspecific(globalkey, gs);
617
#elif defined HAVE_WIN32_THREADS
618
#ifndef USE_TLS
619
    TlsSetValue(globalkey, gs);
620
#endif
621
#ifdef USE_WAIT_DTOR
622
    xmlRegisterGlobalStateDtor(gs);
623
#endif
624
#endif
625
17.0k
}
626
627
const xmlError *
628
0
__xmlLastError(void) {
629
0
    return(&xmlGetThreadLocalStorage(0)->lastError);
630
0
}
631
632
int *
633
37.2k
__xmlDoValidityCheckingDefaultValue(void) {
634
37.2k
    return(&xmlGetThreadLocalStorage(0)->doValidityCheckingDefaultValue);
635
37.2k
}
636
637
int *
638
1.03M
__xmlGetWarningsDefaultValue(void) {
639
1.03M
    return(&xmlGetThreadLocalStorage(0)->getWarningsDefaultValue);
640
1.03M
}
641
642
int *
643
37.2k
__xmlKeepBlanksDefaultValue(void) {
644
37.2k
    return(&xmlGetThreadLocalStorage(0)->keepBlanksDefaultValue);
645
37.2k
}
646
647
int *
648
0
__xmlLineNumbersDefaultValue(void) {
649
0
    return(&lineNumbersDefaultValue);
650
0
}
651
652
int *
653
37.2k
__xmlLoadExtDtdDefaultValue(void) {
654
37.2k
    return(&xmlGetThreadLocalStorage(0)->loadExtDtdDefaultValue);
655
37.2k
}
656
657
int *
658
37.2k
__xmlPedanticParserDefaultValue(void) {
659
37.2k
    return(&xmlGetThreadLocalStorage(0)->pedanticParserDefaultValue);
660
37.2k
}
661
662
int *
663
37.2k
__xmlSubstituteEntitiesDefaultValue(void) {
664
37.2k
    return(&xmlGetThreadLocalStorage(0)->substituteEntitiesDefaultValue);
665
37.2k
}
666
667
#ifdef LIBXML_OUTPUT_ENABLED
668
int *
669
0
__xmlIndentTreeOutput(void) {
670
0
    return(&xmlGetThreadLocalStorage(0)->indentTreeOutput);
671
0
}
672
673
const char **
674
0
__xmlTreeIndentString(void) {
675
0
    return(&xmlGetThreadLocalStorage(0)->treeIndentString);
676
0
}
677
678
int *
679
0
__xmlSaveNoEmptyTags(void) {
680
0
    return(&xmlGetThreadLocalStorage(0)->saveNoEmptyTags);
681
0
}
682
#endif
683
684
xmlGenericErrorFunc *
685
993k
__xmlGenericError(void) {
686
993k
    return(&xmlGetThreadLocalStorage(0)->genericError);
687
993k
}
688
689
void **
690
13.3M
__xmlGenericErrorContext(void) {
691
13.3M
    return(&xmlGetThreadLocalStorage(0)->genericErrorContext);
692
13.3M
}
693
694
xmlStructuredErrorFunc *
695
993k
__xmlStructuredError(void) {
696
993k
    return(&xmlGetThreadLocalStorage(0)->structuredError);
697
993k
}
698
699
void **
700
0
__xmlStructuredErrorContext(void) {
701
0
    return(&xmlGetThreadLocalStorage(0)->structuredErrorContext);
702
0
}
703
704
xmlRegisterNodeFunc *
705
0
__xmlRegisterNodeDefaultValue(void) {
706
0
    return(&xmlGetThreadLocalStorage(0)->registerNodeDefaultValue);
707
0
}
708
709
xmlDeregisterNodeFunc *
710
0
__xmlDeregisterNodeDefaultValue(void) {
711
0
    return(&xmlGetThreadLocalStorage(0)->deregisterNodeDefaultValue);
712
0
}
713
714
xmlParserInputBufferCreateFilenameFunc *
715
0
__xmlParserInputBufferCreateFilenameValue(void) {
716
0
    return(&xmlGetThreadLocalStorage(0)->parserInputBufferCreateFilenameValue);
717
0
}
718
719
xmlOutputBufferCreateFilenameFunc *
720
0
__xmlOutputBufferCreateFilenameValue(void) {
721
0
    return(&xmlGetThreadLocalStorage(0)->outputBufferCreateFilenameValue);
722
0
}
723
724
#ifdef LIBXML_THREAD_ALLOC_ENABLED
725
xmlMallocFunc *
726
__xmlMalloc(void) {
727
    return(&xmlGetThreadLocalStorage(0)->malloc);
728
}
729
730
xmlMallocFunc *
731
__xmlMallocAtomic(void) {
732
    return(&xmlGetThreadLocalStorage(0)->mallocAtomic);
733
}
734
735
xmlReallocFunc *
736
__xmlRealloc(void) {
737
    return(&xmlGetThreadLocalStorage(0)->realloc);
738
}
739
740
xmlFreeFunc *
741
__xmlFree(void) {
742
    return(&xmlGetThreadLocalStorage(0)->free);
743
}
744
745
xmlStrdupFunc *
746
__xmlMemStrdup(void) {
747
    return(&xmlGetThreadLocalStorage(0)->memStrdup);
748
}
749
#endif /* LIBXML_THREAD_ALLOC_ENABLED */
750
751
/**
752
 * @returns the local RNG state.
753
 */
754
unsigned *
755
57.3k
xmlGetLocalRngState(void) {
756
57.3k
    return(xmlGetThreadLocalStorage(0)->localRngState);
757
57.3k
}
758
759
/**
760
 * Check whether thread-local storage could be allocated.
761
 *
762
 * In cross-platform code running in multithreaded environments, this
763
 * function should be called once in each thread before calling other
764
 * library functions to make sure that thread-local storage was
765
 * allocated properly.
766
 *
767
 * @since 2.12.0
768
 * @returns 0 on success or -1 if a memory allocation failed. A failed
769
 * allocation signals a typically fatal and irrecoverable out-of-memory
770
 * situation. Don't call any library functions in this case.
771
 */
772
int
773
0
xmlCheckThreadLocalStorage(void) {
774
0
#if defined(LIBXML_THREAD_ENABLED) && !defined(USE_TLS)
775
0
    if (xmlGetThreadLocalStorage(1) == NULL)
776
0
        return(-1);
777
0
#endif
778
0
    return(0);
779
0
}
780
781
/**
782
 * @returns a pointer to the global error struct.
783
 */
784
xmlError *
785
993k
xmlGetLastErrorInternal(void) {
786
993k
    return(&xmlGetThreadLocalStorage(0)->lastError);
787
993k
}
788
789
#ifdef USE_DLL_MAIN
790
/**
791
 * Entry point for Windows library. It is being used to free thread-specific
792
 * storage.
793
 *
794
 * @param hinstDLL  handle to DLL instance
795
 * @param fdwReason  Reason code for entry
796
 * @param lpvReserved  generic pointer (depends upon reason code)
797
 * @returns TRUE always
798
 */
799
#if defined(LIBXML_STATIC_FOR_DLL)
800
int
801
xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason,
802
           ATTRIBUTE_UNUSED void *lpvReserved)
803
#else
804
805
/*
806
 * Declare to avoid "no previous prototype for 'DllMain'" warning.
807
 *
808
 * Note that we do NOT want to include this function declaration in
809
 * a public header because it's meant to be called by Windows itself,
810
 * not a program that uses this library.
811
 *
812
 * It is a mistake to export this function, but changing that seems
813
 * to break the ABI.
814
 */
815
XMLPUBFUN BOOL WINAPI
816
DllMain (HINSTANCE hinstDLL,
817
         DWORD     fdwReason,
818
         LPVOID    lpvReserved);
819
820
BOOL WINAPI
821
DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
822
        ATTRIBUTE_UNUSED LPVOID lpvReserved)
823
#endif
824
{
825
    if ((fdwReason == DLL_THREAD_DETACH) ||
826
        (fdwReason == DLL_PROCESS_DETACH)) {
827
#ifdef USE_TLS
828
        xmlFreeGlobalState(&globalState);
829
#else
830
        if (globalkey != TLS_OUT_OF_INDEXES) {
831
            xmlGlobalState *globalval;
832
833
            globalval = (xmlGlobalState *) TlsGetValue(globalkey);
834
            if (globalval) {
835
                xmlFreeGlobalState(globalval);
836
                TlsSetValue(globalkey, NULL);
837
            }
838
        }
839
#endif
840
    }
841
842
#ifndef LIBXML_THREAD_ALLOC_ENABLED
843
    if (fdwReason == DLL_PROCESS_DETACH) {
844
        if (xmlFree == free)
845
            xmlCleanupParser();
846
        if (globalkey != TLS_OUT_OF_INDEXES) {
847
            TlsFree(globalkey);
848
            globalkey = TLS_OUT_OF_INDEXES;
849
        }
850
    }
851
#endif
852
853
    return TRUE;
854
}
855
#endif /* USE_DLL_MAIN */
856
857
/**
858
 * Set per-thread default value.
859
 *
860
 * @deprecated Call #xmlSetGenericErrorFunc in each thread.
861
 *
862
 * @param ctx  user data
863
 * @param handler  error handler
864
 */
865
void
866
0
xmlThrDefSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
867
0
    xmlMutexLock(&xmlThrDefMutex);
868
0
    xmlGenericErrorContextThrDef = ctx;
869
0
    if (handler != NULL)
870
0
  xmlGenericErrorThrDef = handler;
871
0
    else
872
0
  xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc;
873
0
    xmlMutexUnlock(&xmlThrDefMutex);
874
0
}
875
876
/**
877
 * Set per-thread default value.
878
 *
879
 * @deprecated Call #xmlSetStructuredErrorFunc in each thread.
880
 *
881
 * @param ctx  user data
882
 * @param handler  error handler
883
 */
884
void
885
0
xmlThrDefSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) {
886
0
    xmlMutexLock(&xmlThrDefMutex);
887
0
    xmlStructuredErrorContextThrDef = ctx;
888
0
    xmlStructuredErrorThrDef = handler;
889
0
    xmlMutexUnlock(&xmlThrDefMutex);
890
0
}
891
892
/**
893
 * Set per-thread default value.
894
 *
895
 * @deprecated Use xmlParserOption XML_PARSE_DTDVALID.
896
 *
897
 * @param v  new value
898
 * @returns the old value
899
 */
900
0
int xmlThrDefDoValidityCheckingDefaultValue(int v) {
901
0
    int ret;
902
0
    xmlMutexLock(&xmlThrDefMutex);
903
0
    ret = xmlDoValidityCheckingDefaultValueThrDef;
904
0
    xmlDoValidityCheckingDefaultValueThrDef = v;
905
0
    xmlMutexUnlock(&xmlThrDefMutex);
906
0
    return ret;
907
0
}
908
909
/**
910
 * Set per-thread default value.
911
 *
912
 * @deprecated Use xmlParserOption XML_PARSE_NOWARNING.
913
 *
914
 * @param v  new value
915
 * @returns the old value
916
 */
917
0
int xmlThrDefGetWarningsDefaultValue(int v) {
918
0
    int ret;
919
0
    xmlMutexLock(&xmlThrDefMutex);
920
0
    ret = xmlGetWarningsDefaultValueThrDef;
921
0
    xmlGetWarningsDefaultValueThrDef = v;
922
0
    xmlMutexUnlock(&xmlThrDefMutex);
923
0
    return ret;
924
0
}
925
926
#ifdef LIBXML_OUTPUT_ENABLED
927
/**
928
 * Set per-thread default value.
929
 *
930
 * @deprecated Indenting is enabled by default. Use the xmlsave.h API
931
 * and xmlSaveOption XML_SAVE_NO_INDENT to disable indenting.
932
 *
933
 * @param v  new value
934
 * @returns the old value
935
 */
936
0
int xmlThrDefIndentTreeOutput(int v) {
937
0
    int ret;
938
0
    xmlMutexLock(&xmlThrDefMutex);
939
0
    ret = xmlIndentTreeOutputThrDef;
940
0
    xmlIndentTreeOutputThrDef = v;
941
0
    xmlMutexUnlock(&xmlThrDefMutex);
942
0
    return ret;
943
0
}
944
945
/**
946
 * Set per-thread default value.
947
 *
948
 * @deprecated Use the xmlsave.h API and #xmlSaveSetIndentString.
949
 *
950
 * @param v  new value
951
 * @returns the old value
952
 */
953
0
const char * xmlThrDefTreeIndentString(const char * v) {
954
0
    const char * ret;
955
0
    xmlMutexLock(&xmlThrDefMutex);
956
0
    ret = xmlTreeIndentStringThrDef;
957
0
    xmlTreeIndentStringThrDef = v;
958
0
    xmlMutexUnlock(&xmlThrDefMutex);
959
0
    return ret;
960
0
}
961
962
/**
963
 * Set per-thread default value.
964
 *
965
 * @deprecated Use the xmlsave.h API and xmlSaveOption XML_SAVE_NO_EMPTY.
966
 *
967
 * @param v  new value
968
 * @returns the old value
969
 */
970
0
int xmlThrDefSaveNoEmptyTags(int v) {
971
0
    int ret;
972
0
    xmlMutexLock(&xmlThrDefMutex);
973
0
    ret = xmlSaveNoEmptyTagsThrDef;
974
0
    xmlSaveNoEmptyTagsThrDef = v;
975
0
    xmlMutexUnlock(&xmlThrDefMutex);
976
0
    return ret;
977
0
}
978
#endif
979
980
/**
981
 * Set per-thread default value.
982
 *
983
 * @deprecated Whitespace is kept by default. Use xmlParserOption
984
 * XML_PARSE_NOBLANKS to remove whitespace.
985
 *
986
 * @param v  new value
987
 * @returns the old value
988
 */
989
0
int xmlThrDefKeepBlanksDefaultValue(int v) {
990
0
    int ret;
991
0
    xmlMutexLock(&xmlThrDefMutex);
992
0
    ret = xmlKeepBlanksDefaultValueThrDef;
993
0
    xmlKeepBlanksDefaultValueThrDef = v;
994
0
    xmlMutexUnlock(&xmlThrDefMutex);
995
0
    return ret;
996
0
}
997
998
/**
999
 * Set per-thread default value.
1000
 *
1001
 * @deprecated Has no effect.
1002
 *
1003
 * @param v  unused
1004
 * @returns 1
1005
 */
1006
0
int xmlThrDefLineNumbersDefaultValue(int v ATTRIBUTE_UNUSED) {
1007
0
    return 1;
1008
0
}
1009
1010
/**
1011
 * Set per-thread default value.
1012
 *
1013
 * @deprecated Use xmlParserOption XML_PARSE_DTDLOAD.
1014
 *
1015
 * @param v  new value
1016
 * @returns the old value
1017
 */
1018
0
int xmlThrDefLoadExtDtdDefaultValue(int v) {
1019
0
    int ret;
1020
0
    xmlMutexLock(&xmlThrDefMutex);
1021
0
    ret = xmlLoadExtDtdDefaultValueThrDef;
1022
0
    xmlLoadExtDtdDefaultValueThrDef = v;
1023
0
    xmlMutexUnlock(&xmlThrDefMutex);
1024
0
    return ret;
1025
0
}
1026
1027
/**
1028
 * Set per-thread default value.
1029
 *
1030
 * @deprecated Use xmlParserOption XML_PARSE_PEDANTIC.
1031
 *
1032
 * @param v  new value
1033
 * @returns the old value
1034
 */
1035
0
int xmlThrDefPedanticParserDefaultValue(int v) {
1036
0
    int ret;
1037
0
    xmlMutexLock(&xmlThrDefMutex);
1038
0
    ret = xmlPedanticParserDefaultValueThrDef;
1039
0
    xmlPedanticParserDefaultValueThrDef = v;
1040
0
    xmlMutexUnlock(&xmlThrDefMutex);
1041
0
    return ret;
1042
0
}
1043
1044
/**
1045
 * Set per-thread default value.
1046
 *
1047
 * @deprecated Use xmlParserOption XML_PARSE_NOENT.
1048
 *
1049
 * @param v  new value
1050
 * @returns the old value
1051
 */
1052
0
int xmlThrDefSubstituteEntitiesDefaultValue(int v) {
1053
0
    int ret;
1054
0
    xmlMutexLock(&xmlThrDefMutex);
1055
0
    ret = xmlSubstituteEntitiesDefaultValueThrDef;
1056
0
    xmlSubstituteEntitiesDefaultValueThrDef = v;
1057
0
    xmlMutexUnlock(&xmlThrDefMutex);
1058
0
    return ret;
1059
0
}
1060
1061
/**
1062
 * Set per-thread default value.
1063
 *
1064
 * @deprecated This feature will be removed.
1065
 *
1066
 * @param func  new value
1067
 * @returns the old value
1068
 */
1069
xmlRegisterNodeFunc
1070
xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func)
1071
0
{
1072
0
    xmlRegisterNodeFunc old;
1073
1074
0
    xmlMutexLock(&xmlThrDefMutex);
1075
0
    old = xmlRegisterNodeDefaultValueThrDef;
1076
1077
0
    xmlRegisterCallbacks = 1;
1078
0
    xmlRegisterNodeDefaultValueThrDef = func;
1079
0
    xmlMutexUnlock(&xmlThrDefMutex);
1080
1081
0
    return(old);
1082
0
}
1083
1084
/**
1085
 * Set per-thread default value.
1086
 *
1087
 * @deprecated This feature will be removed.
1088
 *
1089
 * @param func  new value
1090
 * @returns the old value
1091
 */
1092
xmlDeregisterNodeFunc
1093
xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func)
1094
0
{
1095
0
    xmlDeregisterNodeFunc old;
1096
1097
0
    xmlMutexLock(&xmlThrDefMutex);
1098
0
    old = xmlDeregisterNodeDefaultValueThrDef;
1099
1100
0
    xmlRegisterCallbacks = 1;
1101
0
    xmlDeregisterNodeDefaultValueThrDef = func;
1102
0
    xmlMutexUnlock(&xmlThrDefMutex);
1103
1104
0
    return(old);
1105
0
}
1106
1107
/**
1108
 * Set per-thread default value.
1109
 *
1110
 * @deprecated Call #xmlParserInputBufferCreateFilenameDefault
1111
 * in each thread.
1112
 *
1113
 * @param func  new value
1114
 * @returns the old value
1115
 */
1116
xmlParserInputBufferCreateFilenameFunc
1117
xmlThrDefParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
1118
0
{
1119
0
    xmlParserInputBufferCreateFilenameFunc old;
1120
1121
0
    xmlMutexLock(&xmlThrDefMutex);
1122
0
    old = xmlParserInputBufferCreateFilenameValueThrDef;
1123
0
    if (old == NULL) {
1124
0
    old = __xmlParserInputBufferCreateFilename;
1125
0
  }
1126
1127
0
    xmlParserInputBufferCreateFilenameValueThrDef = func;
1128
0
    xmlMutexUnlock(&xmlThrDefMutex);
1129
1130
0
    return(old);
1131
0
}
1132
1133
/**
1134
 * Set per-thread default value.
1135
 *
1136
 * @deprecated Call #xmlOutputBufferCreateFilenameDefault
1137
 * in each thread.
1138
 *
1139
 * @param func  new value
1140
 * @returns the old value
1141
 */
1142
xmlOutputBufferCreateFilenameFunc
1143
xmlThrDefOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
1144
0
{
1145
0
    xmlOutputBufferCreateFilenameFunc old;
1146
1147
0
    xmlMutexLock(&xmlThrDefMutex);
1148
0
    old = xmlOutputBufferCreateFilenameValueThrDef;
1149
0
#ifdef LIBXML_OUTPUT_ENABLED
1150
0
    if (old == NULL) {
1151
0
    old = __xmlOutputBufferCreateFilename;
1152
0
  }
1153
0
#endif
1154
0
    xmlOutputBufferCreateFilenameValueThrDef = func;
1155
0
    xmlMutexUnlock(&xmlThrDefMutex);
1156
1157
0
    return(old);
1158
0
}
1159