From d354b2f55e0e58a63efda30bcf549ea690187330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 27 Oct 2023 17:19:08 +0200 Subject: [PATCH 1/2] gmacros: Add fallback definition for weak attribute --- glib/gmacros.h | 1 + 1 file changed, 1 insertion(+) diff --git a/glib/gmacros.h b/glib/gmacros.h index 1be50a45b..2d66c2f0c 100644 --- a/glib/gmacros.h +++ b/glib/gmacros.h @@ -185,6 +185,7 @@ #define g_macro__has_attribute___pure__ G_GNUC_CHECK_VERSION (2, 96) #define g_macro__has_attribute___sentinel__ G_GNUC_CHECK_VERSION (4, 0) #define g_macro__has_attribute___unused__ G_GNUC_CHECK_VERSION (2, 4) +#define g_macro__has_attribute___weak__ G_GNUC_CHECK_VERSION (2, 8) #define g_macro__has_attribute_cleanup G_GNUC_CHECK_VERSION (3, 3) #define g_macro__has_attribute_fallthrough G_GNUC_CHECK_VERSION (6, 0) #define g_macro__has_attribute_may_alias G_GNUC_CHECK_VERSION (3, 3) From fb58d55187dfe1565d10c0c0ffdbaa85376cf0b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 27 Oct 2023 17:19:31 +0200 Subject: [PATCH 2/2] glib-private: Check for LSAN support at runtime when controlling it GLib ignores various leaks that we don't consider as such (like the default gio modules) via the LSAN public interface, however those cases are always ignored when using a non-ASAN compiled glib is used by an ASAN-compiled binary. This makes all the GLib-related programs to fail because of false positive leaks. To avoid this, use the gcc extension for weak linking so that we can control ASAN and LSAN only if the symbols they provide are actually available at runtime. --- glib/glib-private.h | 61 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 6 deletions(-) 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);