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