Coverage Report

Created: 2025-07-18 06:10

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