thread test leaks the name of a thread
To reproduce:
- recent GLib (I used c07f8a70 as a base, with !1905 (merged) applied)
- a recent GNU/Linux system (I used Debian's
unstable
rolling release) - build GLib with gcc AddressSanitizer (
-Db_sanitize=address
in Meson)- I used Debian's gcc 10.2.1-6
- I used UndefinedBehaviourSanitizer too (
-Db_sanitize=address,undefined
) but that probably doesn't matter - clang AddressSanitizer would probably also reproduce this
- if !1905 (merged) has been applied, partially or fully revert commit "tests: Mark tests with AddressSanitizer-detected leaks" to re-expose this leak
- run unit tests, specifically
glib:glib / thread
(akaglib/tests/thread.c
)
Expected result: no memory is leaked and unreachable on process exit.
Actual result:
=================================================================
==2939436==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 2 byte(s) in 1 object(s) allocated from:
#0 0x7efe92c10e8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
#1 0x7efe924e6811 in g_malloc ../../../../../../home/smcv/src/glib/glib/gmem.c:106
#2 0x7efe924e6b43 in g_malloc_n ../../../../../../home/smcv/src/glib/glib/gmem.c:344
#3 0x7efe9255ce3b in g_strdup ../../../../../../home/smcv/src/glib/glib/gstrfuncs.c:364
#4 0x7efe9263d3a1 in g_system_thread_new ../../../../../../home/smcv/src/glib/glib/gthread-posix.c:1284
#5 0x7efe9258305f in g_thread_new_internal ../../../../../../home/smcv/src/glib/glib/gthread.c:931
#6 0x7efe92582fdc in g_thread_try_new ../../../../../../home/smcv/src/glib/glib/gthread.c:914
#7 0x5599bb9eb981 in test_thread4 ../../../../../../home/smcv/src/glib/glib/tests/thread.c:148
#8 0x7efe92578df2 in test_case_run ../../../../../../home/smcv/src/glib/glib/gtestutils.c:2764
#9 0x7efe925799f2 in g_test_run_suite_internal ../../../../../../home/smcv/src/glib/glib/gtestutils.c:2852
#10 0x7efe92579c7c in g_test_run_suite_internal ../../../../../../home/smcv/src/glib/glib/gtestutils.c:2869
#11 0x7efe9257a3a2 in g_test_run_suite ../../../../../../home/smcv/src/glib/glib/gtestutils.c:2946
#12 0x7efe92576a72 in g_test_run ../../../../../../home/smcv/src/glib/glib/gtestutils.c:2157
#13 0x5599bb9ec041 in main ../../../../../../home/smcv/src/glib/glib/tests/thread.c:221
#14 0x7efe9150bd09 in __libc_start_main ../csu/libc-start.c:308
SUMMARY: AddressSanitizer: 2 byte(s) leaked in 1 allocation(s).
This is part of test_thread4()
, which attempts to create a thread under a prohibitively small RLIMIT_NPROC
.
The leak is the thread object's name:
alThread *
g_system_thread_new (GThreadFunc proxy,
gulong stack_size,
const GThreadSchedulerSettings *scheduler_settings,
const char *name,
GThreadFunc func,
gpointer data,
GError **error)
{
GThreadPosix *thread;
GRealThread *base_thread;
pthread_attr_t attr;
gint ret;
thread = g_slice_new0 (GThreadPosix);
base_thread = (GRealThread*)thread;
base_thread->ref_count = 2;
base_thread->ours = TRUE;
base_thread->thread.joinable = TRUE;
base_thread->thread.func = func;
base_thread->thread.data = data;
base_thread->name = g_strdup (name); <<< HERE
thread->scheduler_settings = scheduler_settings;
thread->proxy = proxy;
It looks as though g_thread_proxy()
sets the thread's name, and then frees base_thread->name
and sets it to NULL. However, if the rlimit does not allow the thread to start, then g_thread_proxy()
never runs.
One possible solution would be for g_system_thread_free()
to free base_thread->name
if it is still non-NULL. However, I don't know whether that would be thread-safe vs. concurrent modification in g_thread_proxy()
.
For now, I've marked this test g_test_incomplete()
when running under AddressSanitizer, so that we can run the rest of the test-suite under AddressSanitizer and at least make sure we don't regress.