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