diff --git a/glib/glib-private.h b/glib/glib-private.h index f49e38f7b..8053f1d8c 100644 --- a/glib/glib-private.h +++ b/glib/glib-private.h @@ -37,14 +37,51 @@ /* * %_GLIB_ADDRESS_SANITIZER: * - * Private macro defined if the AddressSanitizer is in use. + * Private macro defined if the AddressSanitizer is in use by GLib itself. */ #define _GLIB_ADDRESS_SANITIZER #include +/* If GLib itself is not compiled with ASAN sanitizer we may still want to + * control it in case it's linked by the loading application, so we need to + * do this check dynamically. + * However MinGW doesn't support weak attribute properly (even if it advertises + * it), so we ignore it in such case since it's not convenient to go through + * dlsym(). + * Under MSVC we could use alternatename, but it doesn't seem to be as reliable + * as we'd like: https://stackoverflow.com/a/11529277/210151 and + * https://devblogs.microsoft.com/oldnewthing/20200731-00/?p=104024 + */ +#elif defined (G_OS_UNIX) && g_macro__has_attribute (weak) + +#define HAS_DYNAMIC_ASAN_LOADING + +void __lsan_enable (void) __attribute__ ((weak)); +void __lsan_disable (void) __attribute__ ((weak)); +void __lsan_ignore_object (const void *p) __attribute__ ((weak)); + #endif +/* + * g_leak_sanitizer_is_supported: + * + * Checks at runtime if LeakSanitizer is currently supported by the running + * binary. This may imply that GLib itself is not compiled with sanitizer + * but that the loading program is. + */ +static inline gboolean +g_leak_sanitizer_is_supported (void) +{ +#if defined (_GLIB_ADDRESS_SANITIZER) + return TRUE; +#elif defined (HAS_DYNAMIC_ASAN_LOADING) + return __lsan_enable != NULL && __lsan_ignore_object != NULL; +#else + return FALSE; +#endif +} + /* * g_ignore_leak: * @p: any pointer @@ -57,9 +94,12 @@ static inline void g_ignore_leak (gconstpointer p) { -#ifdef _GLIB_ADDRESS_SANITIZER +#if defined (_GLIB_ADDRESS_SANITIZER) if (p != NULL) __lsan_ignore_object (p); +#elif defined (HAS_DYNAMIC_ASAN_LOADING) + if (p != NULL && __lsan_ignore_object != NULL) + __lsan_ignore_object (p); #endif } @@ -73,9 +113,11 @@ g_ignore_leak (gconstpointer p) static inline void g_ignore_strv_leak (GStrv strv) { -#ifdef _GLIB_ADDRESS_SANITIZER gchar **item; + if (!g_leak_sanitizer_is_supported ()) + return; + if (strv) { g_ignore_leak (strv); @@ -83,7 +125,6 @@ g_ignore_strv_leak (GStrv strv) for (item = strv; *item != NULL; item++) g_ignore_leak (*item); } -#endif } /* @@ -98,8 +139,11 @@ g_ignore_strv_leak (GStrv strv) static inline void g_begin_ignore_leaks (void) { -#ifdef _GLIB_ADDRESS_SANITIZER +#if defined (_GLIB_ADDRESS_SANITIZER) __lsan_disable (); +#elif defined (HAS_DYNAMIC_ASAN_LOADING) + if (__lsan_disable != NULL) + __lsan_disable (); #endif } @@ -112,11 +156,16 @@ g_begin_ignore_leaks (void) static inline void g_end_ignore_leaks (void) { -#ifdef _GLIB_ADDRESS_SANITIZER +#if defined (_GLIB_ADDRESS_SANITIZER) __lsan_enable (); +#elif defined (HAS_DYNAMIC_ASAN_LOADING) + if (__lsan_enable != NULL) + __lsan_enable (); #endif } +#undef HAS_DYNAMIC_ASAN_LOADING + GMainContext * g_get_worker_context (void); gboolean g_check_setuid (void); GMainContext * g_main_context_new_with_next_id (guint next_id);