1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-03-25 10:50:08 +03:00

globals: Don't use thread-local storage on Darwin

It seems that thread-local storage destructors are run before pthread
thread-specific data destructors on Darwin, defeating our scheme to use
TSD to clean up TLS.

Here's an example program that reports a use-after-free when compiled
with `-fsanitize=address` on macOS:

    #include <pthread.h>

    typedef struct {
	int v;
    } my_struct;

    static _Thread_local my_struct tls;
    pthread_key_t key;

    void dtor(void *tsd) {
	my_struct *s = (my_struct *) tsd;
	/*
	 * This will crash ASan, apparently because
	 * TLS has already been freed.
	 */
	s->v = 1;
    }

    void *thread(void *p) {
	pthread_setspecific(key, &tls);
	return NULL;
    }

    int main(void) {
	pthread_key_create(&key, dtor);

	pthread_t handle;
	pthread_create(&handle, NULL, thread, NULL);
	pthread_join(handle, NULL);

	return 0;
    }
This commit is contained in:
Nick Wellnhofer 2023-09-22 13:37:28 +02:00
parent 45470611b0
commit bc4e82ff42

View File

@ -64,13 +64,6 @@
#define IS_MAIN_THREAD 1
#endif
static int parserInitialized;
/*
* Mutex to protect "ForNewThreads" variables
*/
static xmlMutex xmlThrDefMutex;
#define XML_DECLARE_MEMBER(name, type, attrs) \
type gs_##name;
@ -94,9 +87,25 @@ XML_GLOBALS_TREE
#undef XML_OP
};
static int parserInitialized;
/*
* Mutex to protect "ForNewThreads" variables
*/
static xmlMutex xmlThrDefMutex;
#ifdef LIBXML_THREAD_ENABLED
#ifdef XML_THREAD_LOCAL
/*
* On Darwin, thread-local storage destructors seem to be run before
* pthread thread-specific data destructors. This causes ASan to
* report a use-after-free.
*/
#if defined(XML_THREAD_LOCAL) && !defined(__APPLE__)
#define USE_TLS
#endif
#ifdef USE_TLS
static XML_THREAD_LOCAL xmlGlobalState globalState;
#endif
@ -125,7 +134,7 @@ static pthread_t mainthread;
#elif defined HAVE_WIN32_THREADS
#ifndef XML_THREAD_LOCAL
#ifndef USE_TLS
static DWORD globalkey = TLS_OUT_OF_INDEXES;
#endif
static DWORD mainthread;
@ -564,7 +573,7 @@ void xmlInitGlobalsInternal(void) {
pthread_key_create(&globalkey, xmlFreeGlobalState);
mainthread = pthread_self();
#elif defined(HAVE_WIN32_THREADS)
#ifndef XML_THREAD_LOCAL
#ifndef USE_TLS
globalkey = TlsAlloc();
#endif
mainthread = GetCurrentThreadId();
@ -599,7 +608,7 @@ void xmlCleanupGlobalsInternal(void) {
#endif /* XML_PTHREAD_WEAK */
pthread_key_delete(globalkey);
#elif defined(HAVE_WIN32_THREADS)
#ifndef XML_THREAD_LOCAL
#ifndef USE_TLS
if (globalkey != TLS_OUT_OF_INDEXES) {
TlsFree(globalkey);
globalkey = TLS_OUT_OF_INDEXES;
@ -684,7 +693,7 @@ xmlFreeGlobalState(void *state)
* so changes are dangerous.
*/
xmlResetError(&(gs->gs_xmlLastError));
#ifndef XML_THREAD_LOCAL
#ifndef USE_TLS
free(state);
#endif
}
@ -782,7 +791,7 @@ xmlInitGlobalState(xmlGlobalStatePtr gs) {
#ifdef HAVE_POSIX_THREADS
pthread_setspecific(globalkey, gs);
#elif defined HAVE_WIN32_THREADS
#ifndef XML_THREAD_LOCAL
#ifndef USE_TLS
TlsSetValue(globalkey, gs);
#endif
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
@ -793,7 +802,7 @@ xmlInitGlobalState(xmlGlobalStatePtr gs) {
gs->initialized = 1;
}
#ifndef XML_THREAD_LOCAL
#ifndef USE_TLS
/**
* xmlNewGlobalState:
*
@ -835,7 +844,7 @@ xmlGetThreadLocalStorage(int allowFailure) {
(void) allowFailure;
#ifdef XML_THREAD_LOCAL
#ifdef USE_TLS
gs = &globalState;
if (gs->initialized == 0)
xmlInitGlobalState(gs);
@ -907,7 +916,7 @@ __xmlParserVersion(void) {
*/
int
xmlCheckThreadLocalStorage(void) {
#if defined(LIBXML_THREAD_ENABLED) && !defined(XML_THREAD_LOCAL)
#if defined(LIBXML_THREAD_ENABLED) && !defined(USE_TLS)
if ((!xmlIsMainThreadInternal()) && (xmlGetThreadLocalStorage(1) == NULL))
return(-1);
#endif
@ -949,7 +958,7 @@ DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
{
switch (fdwReason) {
case DLL_THREAD_DETACH:
#ifdef XML_THREAD_LOCAL
#ifdef USE_TLS
xmlFreeGlobalState(&globalState);
#else
if (globalkey != TLS_OUT_OF_INDEXES) {