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