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