Coverage Report

Created: 2025-08-26 07:06

/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/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
1.98k
xmlPosixStrdup(const char *cur) {
201
1.98k
    return((char*) xmlCharStrdup(cur));
202
1.98k
}
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
1
void xmlInitGlobalsInternal(void) {
358
1
    xmlInitMutex(&xmlThrDefMutex);
359
360
1
#ifdef HAVE_POSIX_THREADS
361
1
    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
1
}
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
0
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
0
#ifdef HAVE_POSIX_THREADS
392
    /*
393
     * Free thread-specific data of last thread before calling
394
     * pthread_key_delete.
395
     */
396
0
    xmlGlobalState *gs = pthread_getspecific(globalkey);
397
0
    if (gs != NULL)
398
0
        xmlFreeGlobalState(gs);
399
0
    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
        TlsFree(globalkey);
404
        globalkey = TLS_OUT_OF_INDEXES;
405
    }
406
#endif
407
#else /* no thread support */
408
    xmlResetError(&globalState.lastError);
409
#endif
410
411
0
    xmlCleanupMutex(&xmlThrDefMutex);
412
0
}
413
414
#ifdef LIBXML_THREAD_ENABLED
415
416
static void
417
xmlFreeGlobalState(void *state)
418
0
{
419
0
    xmlGlobalState *gs = (xmlGlobalState *) state;
420
421
    /*
422
     * Free any memory allocated in the thread's error struct. If it
423
     * weren't for this indirect allocation, we wouldn't need
424
     * a destructor with thread-local storage at all!
425
     */
426
0
    xmlResetError(&gs->lastError);
427
0
#ifndef USE_TLS
428
0
    free(state);
429
0
#endif
430
0
}
431
432
#if defined(USE_WAIT_DTOR)
433
static void WINAPI
434
xmlGlobalStateDtor(void *ctxt, unsigned char timedOut ATTRIBUTE_UNUSED) {
435
    xmlGlobalStatePtr gs = ctxt;
436
437
    UnregisterWait(gs->waitHandle);
438
    CloseHandle(gs->threadHandle);
439
    xmlFreeGlobalState(gs);
440
}
441
442
static int
443
xmlRegisterGlobalStateDtor(xmlGlobalState *gs) {
444
    void *processHandle = GetCurrentProcess();
445
    void *threadHandle;
446
    void *waitHandle;
447
448
    if (DuplicateHandle(processHandle, GetCurrentThread(), processHandle,
449
                &threadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS) == 0) {
450
        return(-1);
451
    }
452
453
    if (RegisterWaitForSingleObject(&waitHandle, threadHandle,
454
                xmlGlobalStateDtor, gs, INFINITE, WT_EXECUTEONLYONCE) == 0) {
455
        CloseHandle(threadHandle);
456
        return(-1);
457
    }
458
459
    gs->threadHandle = threadHandle;
460
    gs->waitHandle = waitHandle;
461
    return(0);
462
}
463
#endif /* USE_WAIT_DTOR */
464
465
#ifndef USE_TLS
466
/**
467
 * Allocates a global state. This structure is used to
468
 * hold all data for use by a thread when supporting backwards compatibility
469
 * of libxml2 to pre-thread-safe behaviour.
470
 *
471
 * @returns the newly allocated xmlGlobalState or NULL in case of error
472
 */
473
static xmlGlobalStatePtr
474
xmlNewGlobalState(int allowFailure)
475
1
{
476
1
    xmlGlobalState *gs;
477
478
    /*
479
     * We use malloc/free to allow accessing globals before setting
480
     * custom memory allocators.
481
     */
482
1
    gs = malloc(sizeof(xmlGlobalState));
483
1
    if (gs == NULL) {
484
0
        if (allowFailure)
485
0
            return(NULL);
486
487
        /*
488
         * If an application didn't call xmlCheckThreadLocalStorage to make
489
         * sure that global state could be allocated, it's too late to
490
         * handle the error.
491
         */
492
0
        xmlAbort("libxml2: Failed to allocate globals for thread\n"
493
0
                 "libxml2: See xmlCheckThreadLocalStorage\n");
494
0
    }
495
496
1
    memset(gs, 0, sizeof(xmlGlobalState));
497
1
    xmlInitGlobalState(gs);
498
1
    return (gs);
499
1
}
500
#endif
501
502
static xmlGlobalStatePtr
503
1.98M
xmlGetThreadLocalStorage(int allowFailure) {
504
1.98M
    xmlGlobalState *gs;
505
506
1.98M
    (void) allowFailure;
507
508
1.98M
    xmlInitParser();
509
510
#ifdef USE_TLS
511
    gs = &globalState;
512
    if (gs->initialized == 0)
513
        xmlInitGlobalState(gs);
514
#elif defined(HAVE_POSIX_THREADS)
515
    gs = (xmlGlobalState *) pthread_getspecific(globalkey);
516
1.98M
    if (gs == NULL)
517
1
        gs = xmlNewGlobalState(allowFailure);
518
#elif defined(HAVE_WIN32_THREADS)
519
    gs = (xmlGlobalState *) TlsGetValue(globalkey);
520
    if (gs == NULL)
521
        gs = xmlNewGlobalState(allowFailure);
522
#else
523
    gs = NULL;
524
#endif
525
526
1.98M
    return(gs);
527
1.98M
}
528
529
#else /* LIBXML_THREAD_ENABLED */
530
531
static xmlGlobalStatePtr
532
xmlGetThreadLocalStorage(int allowFailure ATTRIBUTE_UNUSED) {
533
    return(&globalState);
534
}
535
536
#endif /* LIBXML_THREAD_ENABLED */
537
538
static void
539
1
xmlInitGlobalState(xmlGlobalStatePtr gs) {
540
1
    gs->localRngState[0] = xmlGlobalRandom();
541
1
    gs->localRngState[1] = xmlGlobalRandom();
542
543
1
    memset(&gs->lastError, 0, sizeof(xmlError));
544
545
#ifdef LIBXML_THREAD_ALLOC_ENABLED
546
    /* XML_GLOBALS_ALLOC */
547
    gs->free = free;
548
    gs->malloc = malloc;
549
    gs->mallocAtomic = malloc;
550
    gs->realloc = realloc;
551
    gs->memStrdup = xmlPosixStrdup;
552
#endif
553
554
1
    xmlMutexLock(&xmlThrDefMutex);
555
556
    /* XML_GLOBALS_PARSER */
557
1
    gs->doValidityCheckingDefaultValue =
558
1
         xmlDoValidityCheckingDefaultValueThrDef;
559
1
    gs->getWarningsDefaultValue = xmlGetWarningsDefaultValueThrDef;
560
1
    gs->keepBlanksDefaultValue = xmlKeepBlanksDefaultValueThrDef;
561
1
    gs->loadExtDtdDefaultValue = xmlLoadExtDtdDefaultValueThrDef;
562
1
    gs->pedanticParserDefaultValue = xmlPedanticParserDefaultValueThrDef;
563
1
    gs->substituteEntitiesDefaultValue =
564
1
        xmlSubstituteEntitiesDefaultValueThrDef;
565
1
#ifdef LIBXML_OUTPUT_ENABLED
566
1
    gs->indentTreeOutput = xmlIndentTreeOutputThrDef;
567
1
    gs->treeIndentString = xmlTreeIndentStringThrDef;
568
1
    gs->saveNoEmptyTags = xmlSaveNoEmptyTagsThrDef;
569
1
#endif
570
571
    /* XML_GLOBALS_ERROR */
572
1
    gs->genericError = xmlGenericErrorThrDef;
573
1
    gs->structuredError = xmlStructuredErrorThrDef;
574
1
    gs->genericErrorContext = xmlGenericErrorContextThrDef;
575
1
    gs->structuredErrorContext = xmlStructuredErrorContextThrDef;
576
577
    /* XML_GLOBALS_TREE */
578
1
    gs->registerNodeDefaultValue = xmlRegisterNodeDefaultValueThrDef;
579
1
    gs->deregisterNodeDefaultValue = xmlDeregisterNodeDefaultValueThrDef;
580
581
    /* XML_GLOBALS_IO */
582
1
    gs->parserInputBufferCreateFilenameValue =
583
1
        xmlParserInputBufferCreateFilenameValueThrDef;
584
1
    gs->outputBufferCreateFilenameValue =
585
1
        xmlOutputBufferCreateFilenameValueThrDef;
586
587
1
    xmlMutexUnlock(&xmlThrDefMutex);
588
589
#ifdef USE_TLS
590
    gs->initialized = 1;
591
#endif
592
593
1
#ifdef HAVE_POSIX_THREADS
594
1
    pthread_setspecific(globalkey, gs);
595
#elif defined HAVE_WIN32_THREADS
596
#ifndef USE_TLS
597
    TlsSetValue(globalkey, gs);
598
#endif
599
#ifdef USE_WAIT_DTOR
600
    xmlRegisterGlobalStateDtor(gs);
601
#endif
602
#endif
603
1
}
604
605
const xmlError *
606
0
__xmlLastError(void) {
607
0
    return(&xmlGetThreadLocalStorage(0)->lastError);
608
0
}
609
610
int *
611
18.0k
__xmlDoValidityCheckingDefaultValue(void) {
612
18.0k
    return(&xmlGetThreadLocalStorage(0)->doValidityCheckingDefaultValue);
613
18.0k
}
614
615
int *
616
372k
__xmlGetWarningsDefaultValue(void) {
617
372k
    return(&xmlGetThreadLocalStorage(0)->getWarningsDefaultValue);
618
372k
}
619
620
int *
621
18.0k
__xmlKeepBlanksDefaultValue(void) {
622
18.0k
    return(&xmlGetThreadLocalStorage(0)->keepBlanksDefaultValue);
623
18.0k
}
624
625
int *
626
0
__xmlLineNumbersDefaultValue(void) {
627
0
    return(&lineNumbersDefaultValue);
628
0
}
629
630
int *
631
18.0k
__xmlLoadExtDtdDefaultValue(void) {
632
18.0k
    return(&xmlGetThreadLocalStorage(0)->loadExtDtdDefaultValue);
633
18.0k
}
634
635
int *
636
18.0k
__xmlPedanticParserDefaultValue(void) {
637
18.0k
    return(&xmlGetThreadLocalStorage(0)->pedanticParserDefaultValue);
638
18.0k
}
639
640
int *
641
18.0k
__xmlSubstituteEntitiesDefaultValue(void) {
642
18.0k
    return(&xmlGetThreadLocalStorage(0)->substituteEntitiesDefaultValue);
643
18.0k
}
644
645
#ifdef LIBXML_OUTPUT_ENABLED
646
int *
647
0
__xmlIndentTreeOutput(void) {
648
0
    return(&xmlGetThreadLocalStorage(0)->indentTreeOutput);
649
0
}
650
651
const char **
652
0
__xmlTreeIndentString(void) {
653
0
    return(&xmlGetThreadLocalStorage(0)->treeIndentString);
654
0
}
655
656
int *
657
0
__xmlSaveNoEmptyTags(void) {
658
0
    return(&xmlGetThreadLocalStorage(0)->saveNoEmptyTags);
659
0
}
660
#endif
661
662
xmlGenericErrorFunc *
663
390k
__xmlGenericError(void) {
664
390k
    return(&xmlGetThreadLocalStorage(0)->genericError);
665
390k
}
666
667
void **
668
390k
__xmlGenericErrorContext(void) {
669
390k
    return(&xmlGetThreadLocalStorage(0)->genericErrorContext);
670
390k
}
671
672
xmlStructuredErrorFunc *
673
354k
__xmlStructuredError(void) {
674
354k
    return(&xmlGetThreadLocalStorage(0)->structuredError);
675
354k
}
676
677
void **
678
0
__xmlStructuredErrorContext(void) {
679
0
    return(&xmlGetThreadLocalStorage(0)->structuredErrorContext);
680
0
}
681
682
xmlRegisterNodeFunc *
683
0
__xmlRegisterNodeDefaultValue(void) {
684
0
    return(&xmlGetThreadLocalStorage(0)->registerNodeDefaultValue);
685
0
}
686
687
xmlDeregisterNodeFunc *
688
0
__xmlDeregisterNodeDefaultValue(void) {
689
0
    return(&xmlGetThreadLocalStorage(0)->deregisterNodeDefaultValue);
690
0
}
691
692
xmlParserInputBufferCreateFilenameFunc *
693
0
__xmlParserInputBufferCreateFilenameValue(void) {
694
0
    return(&xmlGetThreadLocalStorage(0)->parserInputBufferCreateFilenameValue);
695
0
}
696
697
xmlOutputBufferCreateFilenameFunc *
698
0
__xmlOutputBufferCreateFilenameValue(void) {
699
0
    return(&xmlGetThreadLocalStorage(0)->outputBufferCreateFilenameValue);
700
0
}
701
702
#ifdef LIBXML_THREAD_ALLOC_ENABLED
703
xmlMallocFunc *
704
__xmlMalloc(void) {
705
    return(&xmlGetThreadLocalStorage(0)->malloc);
706
}
707
708
xmlMallocFunc *
709
__xmlMallocAtomic(void) {
710
    return(&xmlGetThreadLocalStorage(0)->mallocAtomic);
711
}
712
713
xmlReallocFunc *
714
__xmlRealloc(void) {
715
    return(&xmlGetThreadLocalStorage(0)->realloc);
716
}
717
718
xmlFreeFunc *
719
__xmlFree(void) {
720
    return(&xmlGetThreadLocalStorage(0)->free);
721
}
722
723
xmlStrdupFunc *
724
__xmlMemStrdup(void) {
725
    return(&xmlGetThreadLocalStorage(0)->memStrdup);
726
}
727
#endif /* LIBXML_THREAD_ALLOC_ENABLED */
728
729
/**
730
 * @returns the local RNG state.
731
 */
732
unsigned *
733
28.5k
xmlGetLocalRngState(void) {
734
28.5k
    return(xmlGetThreadLocalStorage(0)->localRngState);
735
28.5k
}
736
737
/**
738
 * Check whether thread-local storage could be allocated.
739
 *
740
 * In cross-platform code running in multithreaded environments, this
741
 * function should be called once in each thread before calling other
742
 * library functions to make sure that thread-local storage was
743
 * allocated properly.
744
 *
745
 * @since 2.12.0
746
 * @returns 0 on success or -1 if a memory allocation failed. A failed
747
 * allocation signals a typically fatal and irrecoverable out-of-memory
748
 * situation. Don't call any library functions in this case.
749
 */
750
int
751
0
xmlCheckThreadLocalStorage(void) {
752
0
#if defined(LIBXML_THREAD_ENABLED) && !defined(USE_TLS)
753
0
    if (xmlGetThreadLocalStorage(1) == NULL)
754
0
        return(-1);
755
0
#endif
756
0
    return(0);
757
0
}
758
759
/**
760
 * @returns a pointer to the global error struct.
761
 */
762
xmlError *
763
354k
xmlGetLastErrorInternal(void) {
764
354k
    return(&xmlGetThreadLocalStorage(0)->lastError);
765
354k
}
766
767
#ifdef USE_DLL_MAIN
768
/**
769
 * Entry point for Windows library. It is being used to free thread-specific
770
 * storage.
771
 *
772
 * @param hinstDLL  handle to DLL instance
773
 * @param fdwReason  Reason code for entry
774
 * @param lpvReserved  generic pointer (depends upon reason code)
775
 * @returns TRUE always
776
 */
777
#if defined(LIBXML_STATIC_FOR_DLL)
778
int
779
xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason,
780
           ATTRIBUTE_UNUSED void *lpvReserved)
781
#else
782
/* declare to avoid "no previous prototype for 'DllMain'" warning */
783
/* Note that we do NOT want to include this function declaration in
784
   a public header because it's meant to be called by Windows itself,
785
   not a program that uses this library.  This also has to be exported. */
786
787
XMLPUBFUN BOOL WINAPI
788
DllMain (HINSTANCE hinstDLL,
789
         DWORD     fdwReason,
790
         LPVOID    lpvReserved);
791
792
BOOL WINAPI
793
DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
794
        ATTRIBUTE_UNUSED LPVOID lpvReserved)
795
#endif
796
{
797
    if ((fdwReason == DLL_THREAD_DETACH) ||
798
        (fdwReason == DLL_PROCESS_DETACH)) {
799
#ifdef USE_TLS
800
        xmlFreeGlobalState(&globalState);
801
#else
802
        if (globalkey != TLS_OUT_OF_INDEXES) {
803
            xmlGlobalState *globalval;
804
805
            globalval = (xmlGlobalState *) TlsGetValue(globalkey);
806
            if (globalval) {
807
                xmlFreeGlobalState(globalval);
808
                TlsSetValue(globalkey, NULL);
809
            }
810
        }
811
#endif
812
    }
813
814
#ifndef LIBXML_THREAD_ALLOC_ENABLED
815
    if (fdwReason == DLL_PROCESS_DETACH) {
816
        if (xmlFree == free)
817
            xmlCleanupParser();
818
        if (globalkey != TLS_OUT_OF_INDEXES) {
819
            TlsFree(globalkey);
820
            globalkey = TLS_OUT_OF_INDEXES;
821
        }
822
    }
823
#endif
824
825
    return TRUE;
826
}
827
#endif /* USE_DLL_MAIN */
828
829
/**
830
 * Set per-thread default value.
831
 *
832
 * @deprecated Call #xmlSetGenericErrorFunc in each thread.
833
 *
834
 * @param ctx  user data
835
 * @param handler  error handler
836
 */
837
void
838
0
xmlThrDefSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
839
0
    xmlMutexLock(&xmlThrDefMutex);
840
0
    xmlGenericErrorContextThrDef = ctx;
841
0
    if (handler != NULL)
842
0
  xmlGenericErrorThrDef = handler;
843
0
    else
844
0
  xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc;
845
0
    xmlMutexUnlock(&xmlThrDefMutex);
846
0
}
847
848
/**
849
 * Set per-thread default value.
850
 *
851
 * @deprecated Call #xmlSetStructuredErrorFunc in each thread.
852
 *
853
 * @param ctx  user data
854
 * @param handler  error handler
855
 */
856
void
857
0
xmlThrDefSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) {
858
0
    xmlMutexLock(&xmlThrDefMutex);
859
0
    xmlStructuredErrorContextThrDef = ctx;
860
0
    xmlStructuredErrorThrDef = handler;
861
0
    xmlMutexUnlock(&xmlThrDefMutex);
862
0
}
863
864
/**
865
 * Set per-thread default value.
866
 *
867
 * @deprecated Use xmlParserOption XML_PARSE_DTDVALID.
868
 *
869
 * @param v  new value
870
 * @returns the old value
871
 */
872
0
int xmlThrDefDoValidityCheckingDefaultValue(int v) {
873
0
    int ret;
874
0
    xmlMutexLock(&xmlThrDefMutex);
875
0
    ret = xmlDoValidityCheckingDefaultValueThrDef;
876
0
    xmlDoValidityCheckingDefaultValueThrDef = v;
877
0
    xmlMutexUnlock(&xmlThrDefMutex);
878
0
    return ret;
879
0
}
880
881
/**
882
 * Set per-thread default value.
883
 *
884
 * @deprecated Use xmlParserOption XML_PARSE_NOWARNING.
885
 *
886
 * @param v  new value
887
 * @returns the old value
888
 */
889
0
int xmlThrDefGetWarningsDefaultValue(int v) {
890
0
    int ret;
891
0
    xmlMutexLock(&xmlThrDefMutex);
892
0
    ret = xmlGetWarningsDefaultValueThrDef;
893
0
    xmlGetWarningsDefaultValueThrDef = v;
894
0
    xmlMutexUnlock(&xmlThrDefMutex);
895
0
    return ret;
896
0
}
897
898
#ifdef LIBXML_OUTPUT_ENABLED
899
/**
900
 * Set per-thread default value.
901
 *
902
 * @deprecated Indenting is enabled by default. Use the xmlsave.h API
903
 * and xmlSaveOption XML_SAVE_NO_INDENT to disable indenting.
904
 *
905
 * @param v  new value
906
 * @returns the old value
907
 */
908
0
int xmlThrDefIndentTreeOutput(int v) {
909
0
    int ret;
910
0
    xmlMutexLock(&xmlThrDefMutex);
911
0
    ret = xmlIndentTreeOutputThrDef;
912
0
    xmlIndentTreeOutputThrDef = v;
913
0
    xmlMutexUnlock(&xmlThrDefMutex);
914
0
    return ret;
915
0
}
916
917
/**
918
 * Set per-thread default value.
919
 *
920
 * @deprecated Use the xmlsave.h API and #xmlSaveSetIndentString.
921
 *
922
 * @param v  new value
923
 * @returns the old value
924
 */
925
0
const char * xmlThrDefTreeIndentString(const char * v) {
926
0
    const char * ret;
927
0
    xmlMutexLock(&xmlThrDefMutex);
928
0
    ret = xmlTreeIndentStringThrDef;
929
0
    xmlTreeIndentStringThrDef = v;
930
0
    xmlMutexUnlock(&xmlThrDefMutex);
931
0
    return ret;
932
0
}
933
934
/**
935
 * Set per-thread default value.
936
 *
937
 * @deprecated Use the xmlsave.h API and xmlSaveOption XML_SAVE_NO_EMPTY.
938
 *
939
 * @param v  new value
940
 * @returns the old value
941
 */
942
0
int xmlThrDefSaveNoEmptyTags(int v) {
943
0
    int ret;
944
0
    xmlMutexLock(&xmlThrDefMutex);
945
0
    ret = xmlSaveNoEmptyTagsThrDef;
946
0
    xmlSaveNoEmptyTagsThrDef = v;
947
0
    xmlMutexUnlock(&xmlThrDefMutex);
948
0
    return ret;
949
0
}
950
#endif
951
952
/**
953
 * Set per-thread default value.
954
 *
955
 * @deprecated Whitespace is kept by default. Use xmlParserOption
956
 * XML_PARSE_NOBLANKS to remove whitespace.
957
 *
958
 * @param v  new value
959
 * @returns the old value
960
 */
961
0
int xmlThrDefKeepBlanksDefaultValue(int v) {
962
0
    int ret;
963
0
    xmlMutexLock(&xmlThrDefMutex);
964
0
    ret = xmlKeepBlanksDefaultValueThrDef;
965
0
    xmlKeepBlanksDefaultValueThrDef = v;
966
0
    xmlMutexUnlock(&xmlThrDefMutex);
967
0
    return ret;
968
0
}
969
970
/**
971
 * Set per-thread default value.
972
 *
973
 * @deprecated Has no effect.
974
 *
975
 * @param v  unused
976
 * @returns 1
977
 */
978
0
int xmlThrDefLineNumbersDefaultValue(int v ATTRIBUTE_UNUSED) {
979
0
    return 1;
980
0
}
981
982
/**
983
 * Set per-thread default value.
984
 *
985
 * @deprecated Use xmlParserOption XML_PARSE_DTDLOAD.
986
 *
987
 * @param v  new value
988
 * @returns the old value
989
 */
990
0
int xmlThrDefLoadExtDtdDefaultValue(int v) {
991
0
    int ret;
992
0
    xmlMutexLock(&xmlThrDefMutex);
993
0
    ret = xmlLoadExtDtdDefaultValueThrDef;
994
0
    xmlLoadExtDtdDefaultValueThrDef = v;
995
0
    xmlMutexUnlock(&xmlThrDefMutex);
996
0
    return ret;
997
0
}
998
999
/**
1000
 * Set per-thread default value.
1001
 *
1002
 * @deprecated Use xmlParserOption XML_PARSE_PEDANTIC.
1003
 *
1004
 * @param v  new value
1005
 * @returns the old value
1006
 */
1007
0
int xmlThrDefPedanticParserDefaultValue(int v) {
1008
0
    int ret;
1009
0
    xmlMutexLock(&xmlThrDefMutex);
1010
0
    ret = xmlPedanticParserDefaultValueThrDef;
1011
0
    xmlPedanticParserDefaultValueThrDef = v;
1012
0
    xmlMutexUnlock(&xmlThrDefMutex);
1013
0
    return ret;
1014
0
}
1015
1016
/**
1017
 * Set per-thread default value.
1018
 *
1019
 * @deprecated Use xmlParserOption XML_PARSE_NOENT.
1020
 *
1021
 * @param v  new value
1022
 * @returns the old value
1023
 */
1024
0
int xmlThrDefSubstituteEntitiesDefaultValue(int v) {
1025
0
    int ret;
1026
0
    xmlMutexLock(&xmlThrDefMutex);
1027
0
    ret = xmlSubstituteEntitiesDefaultValueThrDef;
1028
0
    xmlSubstituteEntitiesDefaultValueThrDef = v;
1029
0
    xmlMutexUnlock(&xmlThrDefMutex);
1030
0
    return ret;
1031
0
}
1032
1033
/**
1034
 * Set per-thread default value.
1035
 *
1036
 * @deprecated This feature will be removed.
1037
 *
1038
 * @param func  new value
1039
 * @returns the old value
1040
 */
1041
xmlRegisterNodeFunc
1042
xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func)
1043
0
{
1044
0
    xmlRegisterNodeFunc old;
1045
1046
0
    xmlMutexLock(&xmlThrDefMutex);
1047
0
    old = xmlRegisterNodeDefaultValueThrDef;
1048
1049
0
    xmlRegisterCallbacks = 1;
1050
0
    xmlRegisterNodeDefaultValueThrDef = func;
1051
0
    xmlMutexUnlock(&xmlThrDefMutex);
1052
1053
0
    return(old);
1054
0
}
1055
1056
/**
1057
 * Set per-thread default value.
1058
 *
1059
 * @deprecated This feature will be removed.
1060
 *
1061
 * @param func  new value
1062
 * @returns the old value
1063
 */
1064
xmlDeregisterNodeFunc
1065
xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func)
1066
0
{
1067
0
    xmlDeregisterNodeFunc old;
1068
1069
0
    xmlMutexLock(&xmlThrDefMutex);
1070
0
    old = xmlDeregisterNodeDefaultValueThrDef;
1071
1072
0
    xmlRegisterCallbacks = 1;
1073
0
    xmlDeregisterNodeDefaultValueThrDef = func;
1074
0
    xmlMutexUnlock(&xmlThrDefMutex);
1075
1076
0
    return(old);
1077
0
}
1078
1079
/**
1080
 * Set per-thread default value.
1081
 *
1082
 * @deprecated Call #xmlParserInputBufferCreateFilenameDefault
1083
 * in each thread.
1084
 *
1085
 * @param func  new value
1086
 * @returns the old value
1087
 */
1088
xmlParserInputBufferCreateFilenameFunc
1089
xmlThrDefParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
1090
0
{
1091
0
    xmlParserInputBufferCreateFilenameFunc old;
1092
1093
0
    xmlMutexLock(&xmlThrDefMutex);
1094
0
    old = xmlParserInputBufferCreateFilenameValueThrDef;
1095
0
    if (old == NULL) {
1096
0
    old = __xmlParserInputBufferCreateFilename;
1097
0
  }
1098
1099
0
    xmlParserInputBufferCreateFilenameValueThrDef = func;
1100
0
    xmlMutexUnlock(&xmlThrDefMutex);
1101
1102
0
    return(old);
1103
0
}
1104
1105
/**
1106
 * Set per-thread default value.
1107
 *
1108
 * @deprecated Call #xmlOutputBufferCreateFilenameDefault
1109
 * in each thread.
1110
 *
1111
 * @param func  new value
1112
 * @returns the old value
1113
 */
1114
xmlOutputBufferCreateFilenameFunc
1115
xmlThrDefOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
1116
0
{
1117
0
    xmlOutputBufferCreateFilenameFunc old;
1118
1119
0
    xmlMutexLock(&xmlThrDefMutex);
1120
0
    old = xmlOutputBufferCreateFilenameValueThrDef;
1121
0
#ifdef LIBXML_OUTPUT_ENABLED
1122
0
    if (old == NULL) {
1123
0
    old = __xmlOutputBufferCreateFilename;
1124
0
  }
1125
0
#endif
1126
0
    xmlOutputBufferCreateFilenameValueThrDef = func;
1127
0
    xmlMutexUnlock(&xmlThrDefMutex);
1128
1129
0
    return(old);
1130
0
}
1131