Coverage Report

Created: 2025-06-22 06:55

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