diff --git a/gio/tests/cancellable.c b/gio/tests/cancellable.c index d6b52c1ea..1eb7529d6 100644 --- a/gio/tests/cancellable.c +++ b/gio/tests/cancellable.c @@ -22,6 +22,8 @@ #include +#include "glib/glib-private.h" + /* How long to wait in ms for each iteration */ #define WAIT_ITERATION (10) @@ -257,6 +259,11 @@ threaded_dispose_thread_cb (gpointer user_data) static void test_cancellable_source_threaded_dispose (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks lots of GCancellableSource objects, see glib#2309"); + (void) cancelled_cb; + (void) threaded_dispose_thread_cb; +#else ThreadedDisposeData data; GThread *thread = NULL; guint i; @@ -326,6 +333,7 @@ test_cancellable_source_threaded_dispose (void) g_cond_clear (&data.cond); g_ptr_array_unref (cancellables_pending_unref); +#endif } int diff --git a/gio/tests/contenttype.c b/gio/tests/contenttype.c index 3696e3662..71e8b0df6 100644 --- a/gio/tests/contenttype.c +++ b/gio/tests/contenttype.c @@ -1,6 +1,8 @@ #include #include +#include "glib/glib-private.h" + #define g_assert_content_type_equals(s1, s2) \ do { \ const char *__s1 = (s1), *__s2 = (s2); \ @@ -16,6 +18,9 @@ static void test_guess (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks xdgmime internal data, see glib#2310"); +#else gchar *res; gchar *expected; gchar *existing_directory; @@ -126,11 +131,15 @@ test_guess (void) g_assert_false (uncertain); g_free (res); g_free (expected); +#endif } static void test_unknown (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks xdgmime internal data, see glib#2310"); +#else gchar *unknown; gchar *str; @@ -140,11 +149,15 @@ test_unknown (void) g_assert_cmpstr (str, ==, "application/octet-stream"); g_free (str); g_free (unknown); +#endif } static void test_subtype (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks xdgmime internal data, see glib#2310"); +#else gchar *plain; gchar *xml; @@ -156,6 +169,7 @@ test_subtype (void) g_free (plain); g_free (xml); +#endif } static gint @@ -169,6 +183,10 @@ find_mime (gconstpointer a, gconstpointer b) static void test_list (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks xdgmime internal data, see glib#2310"); + (void) find_mime; +#else GList *types; gchar *plain; gchar *xml; @@ -193,11 +211,15 @@ test_list (void) g_free (plain); g_free (xml); +#endif } static void test_executable (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks xdgmime internal data, see glib#2310"); +#else gchar *type; type = g_content_type_from_mime_type ("application/x-executable"); @@ -211,11 +233,15 @@ test_executable (void) type = g_content_type_from_mime_type ("image/png"); g_assert_false (g_content_type_can_be_executable (type)); g_free (type); +#endif } static void test_description (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks xdgmime internal data, see glib#2310"); +#else gchar *type; gchar *desc; @@ -225,11 +251,15 @@ test_description (void) g_free (desc); g_free (type); +#endif } static void test_icon (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks xdgmime internal data, see glib#2310"); +#else gchar *type; GIcon *icon; @@ -266,12 +296,15 @@ test_icon (void) } g_object_unref (icon); g_free (type); +#endif } static void test_symbolic_icon (void) { -#ifndef G_OS_WIN32 +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks xdgmime internal data, see glib#2310"); +#elif !defined(G_OS_WIN32) gchar *type; GIcon *icon; @@ -319,6 +352,9 @@ test_symbolic_icon (void) static void test_tree (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks xdgmime internal data, see glib#2310"); +#else const gchar *tests[] = { "x-content/image-dcf", "x-content/unix-software", @@ -343,11 +379,15 @@ test_tree (void) g_strfreev (types); g_object_unref (file); } +#endif } static void test_type_is_a_special_case (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks xdgmime internal data, see glib#2310"); +#else gboolean res; g_test_bug ("782311"); @@ -359,11 +399,15 @@ test_type_is_a_special_case (void) res = g_content_type_is_a ("anything", "application/octet-stream"); g_assert_true (res); #endif +#endif } static void test_guess_svg_from_data (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks xdgmime internal data, see glib#2310"); +#else const gchar svgfilecontent[] = "\n\ #include +#include "glib/glib-private.h" + #include "gdbus-tests.h" #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_64 @@ -1302,6 +1304,18 @@ static gpointer check_proxies_in_thread (gpointer user_data) { GMainLoop *loop = user_data; +#ifdef _GLIB_ADDRESS_SANITIZER + + /* Silence "Not available before 2.38" when using old API */ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + g_test_incomplete ("FIXME: Leaks a GWeakRef, see glib#2312"); + G_GNUC_END_IGNORE_DEPRECATIONS + + (void) check_thread_proxies; + (void) check_authorize_proxy; + (void) check_bat_proxy; + (void) check_bar_proxy; +#else GMainContext *thread_context; GMainLoop *thread_loop; GError *error; @@ -1370,6 +1384,7 @@ check_proxies_in_thread (gpointer user_data) g_main_loop_unref (thread_loop); g_main_context_unref (thread_context); +#endif /* this breaks out of the loop in main() (below) */ g_main_loop_quit (loop); diff --git a/gio/tests/gmenumodel.c b/gio/tests/gmenumodel.c index fc0fcea48..492daf8c4 100644 --- a/gio/tests/gmenumodel.c +++ b/gio/tests/gmenumodel.c @@ -5,6 +5,8 @@ #include "gdbus-sessionbus.h" +#include "glib/glib-private.h" + static gboolean time_out (gpointer unused G_GNUC_UNUSED) { @@ -1012,11 +1014,17 @@ test_dbus_roundtrip (void) static void test_dbus_peer_roundtrip (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks a GCancellableSource, see glib#2313"); + (void) peer_connection_up; + (void) peer_connection_down; +#else PeerConnection peer; peer_connection_up (&peer); do_roundtrip (peer.server_connection, peer.client_connection); peer_connection_down (&peer); +#endif } static gint items_changed_count; @@ -1145,11 +1153,17 @@ test_dbus_subscriptions (void) static void test_dbus_peer_subscriptions (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks a GCancellableSource, see glib#2313"); + (void) peer_connection_up; + (void) peer_connection_down; +#else PeerConnection peer; peer_connection_up (&peer); do_subscriptions (peer.server_connection, peer.client_connection); peer_connection_down (&peer); +#endif } static gpointer diff --git a/gio/tests/meson.build b/gio/tests/meson.build index aaa54afae..413dbd0c7 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -152,7 +152,8 @@ if host_machine.system() != 'windows' 'trash' : {}, } - if have_rtld_next + # LD_PRELOAD modules don't work so well with AddressSanitizer + if have_rtld_next and get_option('b_sanitize') == 'none' gio_tests += { 'gsocketclient-slow' : { 'depends' : [ diff --git a/gio/tests/testfilemonitor.c b/gio/tests/testfilemonitor.c index b74dc2b71..44c70805b 100644 --- a/gio/tests/testfilemonitor.c +++ b/gio/tests/testfilemonitor.c @@ -4,6 +4,8 @@ #include #include +#include "glib/glib-private.h" + /* These tests were written for the inotify implementation. * Other implementations may require slight adjustments in * the tests, e.g. the length of timeouts @@ -954,6 +956,11 @@ static void test_file_hard_links (Fixture *fixture, gconstpointer user_data) { +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks an inotify data structure, see glib#2311"); + (void) file_hard_links_output; + (void) file_hard_links_step; +#else GError *error = NULL; TestData data; @@ -1004,6 +1011,7 @@ test_file_hard_links (Fixture *fixture, g_object_unref (data.monitor); g_object_unref (data.file); g_object_unref (data.output_stream); +#endif } int diff --git a/glib/glib-private.h b/glib/glib-private.h index 8b7ab132e..8de380d12 100644 --- a/glib/glib-private.h +++ b/glib/glib-private.h @@ -22,6 +22,62 @@ #include "gwakeup.h" #include "gstdioprivate.h" +/* gcc defines __SANITIZE_ADDRESS__, clang sets the address_sanitizer + * feature flag */ +#if defined(__SANITIZE_ADDRESS__) || g_macro__has_feature(address_sanitizer) + +/* + * %_GLIB_ADDRESS_SANITIZER: + * + * Private macro defined if the AddressSanitizer is in use. + */ +#define _GLIB_ADDRESS_SANITIZER + +#include + +#endif + +/* + * g_ignore_leak: + * @p: any pointer + * + * Tell AddressSanitizer and similar tools that if the object pointed to + * by @p is leaked, it is not a problem. Use this to suppress memory leak + * reports when a potentially unreachable pointer is deliberately not + * going to be deallocated. + */ +static inline void +g_ignore_leak (gconstpointer p) +{ +#ifdef _GLIB_ADDRESS_SANITIZER + if (p != NULL) + __lsan_ignore_object (p); +#endif +} + +/* + * g_ignore_strv_leak: + * @strv: (nullable) (array zero-terminated=1): an array of strings + * + * The same as g_ignore_leak(), but for the memory pointed to by @strv, + * and for each element of @strv. + */ +static inline void +g_ignore_strv_leak (GStrv strv) +{ +#ifdef _GLIB_ADDRESS_SANITIZER + gchar **item; + + if (strv) + { + g_ignore_leak (strv); + + for (item = strv; *item != NULL; item++) + g_ignore_leak (*item); + } +#endif +} + GMainContext * g_get_worker_context (void); gboolean g_check_setuid (void); GMainContext * g_main_context_new_with_next_id (guint next_id); diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 473e1b677..5660fc8be 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -309,8 +309,12 @@ * behaviour, to verify that appropriate warnings are given. It might, in some * cases, be useful to turn this off with if running tests under valgrind; * in tests that use g_test_init(), the option `-m no-undefined` disables - * those tests, while `-m undefined` explicitly enables them (the default - * behaviour). + * those tests, while `-m undefined` explicitly enables them (normally + * the default behaviour). + * + * Since GLib 2.68, if GLib was compiled with gcc or clang and + * [AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) + * is enabled, the default changes to not exercising undefined behaviour. * * Returns: %TRUE if tests may provoke programming errors */ @@ -1573,6 +1577,10 @@ void g_return_if_fail (g_test_config_vars->test_initialized == FALSE); mutable_test_config_vars.test_initialized = TRUE; +#ifdef _GLIB_ADDRESS_SANITIZER + mutable_test_config_vars.test_undefined = FALSE; +#endif + va_start (args, argv); while ((option = va_arg (args, char *))) { diff --git a/glib/gutils.c b/glib/gutils.c index 8a5dece33..dad162528 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -1601,6 +1601,7 @@ set_str_if_different (gchar **global_str, /* We have to leak the old value, as user code could be retaining pointers * to it. */ + g_ignore_leak (*global_str); *global_str = g_strdup (new_value); } } @@ -1619,6 +1620,7 @@ set_strv_if_different (gchar ***global_strv, /* We have to leak the old value, as user code could be retaining pointers * to it. */ + g_ignore_strv_leak (*global_strv); *global_strv = g_strdupv ((gchar **) new_value); } } diff --git a/glib/tests/error.c b/glib/tests/error.c index 4f4c6b3c7..48f480222 100644 --- a/glib/tests/error.c +++ b/glib/tests/error.c @@ -1,5 +1,7 @@ #include +#include "glib-private.h" + static void test_overwrite (void) { @@ -120,6 +122,12 @@ test_new_valist_invalid_va (gpointer dummy, g_test_summary ("Test that g_error_new_valist() rejects invalid input"); + if (!g_test_undefined ()) + { + g_test_skip ("Not testing response to programmer error"); + return; + } + for (i = 0; i < G_N_ELEMENTS (tests); i++) { GError *error = NULL, *error_copy = NULL; diff --git a/glib/tests/mainloop.c b/glib/tests/mainloop.c index 563a951de..d43b2cf08 100644 --- a/glib/tests/mainloop.c +++ b/glib/tests/mainloop.c @@ -1645,6 +1645,10 @@ threadf (gpointer data) static void test_mainloop_wait (void) { +#ifdef _GLIB_ADDRESS_SANITIZER + (void) threadf; + g_test_incomplete ("FIXME: Leaks a GMainLoop, see glib#2307"); +#else GMainContext *context; GThread *t1, *t2; @@ -1657,6 +1661,7 @@ test_mainloop_wait (void) g_thread_join (t2); g_main_context_unref (context); +#endif } #endif diff --git a/glib/tests/thread.c b/glib/tests/thread.c index 579ce1fca..2bae96c58 100644 --- a/glib/tests/thread.c +++ b/glib/tests/thread.c @@ -33,6 +33,8 @@ #include +#include "glib/glib-private.h" + #ifdef G_OS_UNIX #include #include @@ -132,7 +134,9 @@ test_thread3 (void) static void test_thread4 (void) { -#ifdef HAVE_PRLIMIT +#ifdef _GLIB_ADDRESS_SANITIZER + g_test_incomplete ("FIXME: Leaks a GSystemThread's name, see glib#2308"); +#elif defined(HAVE_PRLIMIT) struct rlimit ol, nl; GThread *thread; GError *error;