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