TSAN data race in gslice allocator.contention_counters
I have a Qt application that uses QFutureWatcher and QtConcurrent::run to do some expensive data loading in the background and then signal when the data is ready.
Using these widgets in tests run with TSAN results in data race warnings. The warnings come from the glib library, so I wasn't sure if this was an error in Qt's use of glib, or in glib itself.
It seems like it's a data race on allocator->contention_counters
A read happens in gslice.c::allocator_get_magazine_threshold: guint contention_counter = allocator->contention_counters[ix];
And a write happens in gslice.c::magazine_cache_pop_magazine: g_mutex_lock_a (&allocator->magazine_mutex, &allocator->contention_counters[ix]);
(This is with glib v2.54.3 and Qt 5.12.4)
Here's the TSAN output, which I'm hoping is reasonably clear w/o a matching code sample.
WARNING: ThreadSanitizer: data race (pid=3460)
{{ Write of size 4 at 0x7b4000000008 by thread T721 (mutexes: write M310):}}
{{ #0 g_mutex_lock_a glib/gslice.c (libglib_U2_U0.so+0x9b0b7)}}
{{ #1 magazine_cache_pop_magazine glib/gslice.c:723:3 (libglib_U2_U0.so+0x9b0b7)}}
{{ #2 thread_memory_magazine1_reload glib/gslice.c:806:17 (libglib_U2_U0.so+0x9b0b7)}}
{{ #3 g_slice_alloc glib/gslice.c:1019:13 (libglib_U2_U0.so+0x9b0b7)}}
{{ #4 g_slice_alloc0 glib/gslice.c:1056:18 (libglib_U2_U0.so+0x9bd0a)}}
{{ #5 g_thread_self glib/gthread.c:990:16 (libglib_U2_U0.so+0xaedec)}}
{{ #6 conditional_wakeup glib/gmain.c:1140:25 (libglib_U2_U0.so+0x69d86)}}
{{ #7 g_main_context_add_poll_unlocked glib/gmain.c:4321:3 (libglib_U2_U0.so+0x69d86)}}
{{ #8 g_main_context_new glib/gmain.c:658:3 (libglib_U2_U0.so+0x69b6e)}}
{{ #9 QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate(_GMainContext*) qtbase-everywhere-src-5_12_2/src/corelib/kernel/qeventdispatcher_glib.cpp:311:27 (qt_Slibcore.so+0x24a765)}}
{{ #10 QEventDispatcherGlib::QEventDispatcherGlib(QObject*) qtbase-everywhere-src-5_12_2/src/corelib/kernel/qeventdispatcher_glib.cpp:357:38 (qt_Slibcore.so+0x24aa8f)}}
{{ #11 QThreadPrivate::createEventDispatcher(QThreadData*) qtbase-everywhere-src-5_12_2/src/corelib/thread/qthread_unix.cpp:290:20 (qt_Slibcore.so+0x35f364)}}
{{ #12 QThreadData::createEventDispatcher() qtbase-everywhere-src-5_12_2/src/corelib/thread/qthread.cpp:122:36 (qt_Slibcore.so+0x35d35a)}}
{{ #13 ensureEventDispatcher qtbase-everywhere-src-5_12_2/src/corelib/thread/qthread_p.h:264:16 (qt_Slibcore.so+0x35f5e4)}}
{{ #14 QThreadPrivate::start(void*) qtbase-everywhere-src-5_12_2/src/corelib/thread/qthread_unix.cpp:342:15 (qt_Slibcore.so+0x35f5e4)}}
Previous read of size 4 at 0x7b4000000008 by thread T934:
{{ #0 allocator_get_magazine_threshold glib/gslice.c:588:30 (libglib_U2_U0.so+0x9beca)}}
{{ #1 thread_memory_magazine2_is_full glib/gslice.c:839:39 (libglib_U2_U0.so+0x9beca)}}
{{ #2 g_slice_free1 glib/gslice.c:1119:11 (libglib_U2_U0.so+0x9beca)}}
{{ #3 g_thread_unref glib/gthread.c:748:9 (libglib_U2_U0.so+0xaef9f)}}
{{ #4 g_thread_cleanup glib/gthread.c:755:3 (libglib_U2_U0.so+0xaef9f)}}
{{ #5 __nptl_deallocate_tsd.part.3 <null> (libpthread.so.0+0x634f)}}
Location is heap block of size 252 at 0x7b4000000000 allocated by main thread:
{{ #0 calloc llvm/llvm/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:667:5 (9ee74028fd01cbfaab89acc835454f305a958cd447bb3925200f864cd2887309_020027025bc0+0x772f83)}}
{{ #1 g_malloc0 glib/gmem.c:124:13 (libglib_U2_U0.so+0x79778)}}
{{ #2 g_malloc0_n glib/gmem.c:355:10 (libglib_U2_U0.so+0x79778)}}
{{ #3 g_slice_init_nomessage glib/gslice.c:445:40 (libglib_U2_U0.so+0x9b60f)}}
{{ #4 thread_memory_from_self glib/gslice.c:520:9 (libglib_U2_U0.so+0x9b60f)}}
{{ #5 g_slice_alloc glib/gslice.c:1008:10 (libglib_U2_U0.so+0x9aae1)}}
{{ #6 g_hash_table_new_full glib/ghash.c:717:16 (libglib_U2_U0.so+0x51a32)}}
{{ #7 g_hash_table_new glib/ghash.c:680:10 (libglib_U2_U0.so+0x51a32)}}
{{ #8 g_quark_init glib/gquark.c:61:14 (libglib_U2_U0.so+0x86a56)}}
{{ #9 glib_init glib/glib-init.c:273:3 (libglib_U2_U0.so+0x66705)}}
{{ #10 glib_init_ctor glib/glib-init.c:331:3 (libglib_U2_U0.so+0x66731)}}
Mutex M310 (0x7b0c00000e40) created at:
{{ #0 pthread_mutex_init llvm/llvm/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:1219:3 (9ee74028fd01cbfaab89acc835454f305a958cd447bb3925200f864cd2887309_020027025bc0+0x775d60)}}
{{ #1 g_mutex_impl_new glib/gthread-posix.c:105:6 (libglib_U2_U0.so+0xaf039)}}
{{ #2 g_mutex_get_impl glib/gthread-posix.c:129:14 (libglib_U2_U0.so+0xaf27b)}}
{{ #3 g_mutex_trylock glib/gthread-posix.c:257:6 (libglib_U2_U0.so+0xaf27b)}}
{{ #4 g_mutex_lock_a glib/gslice.c:484:8 (libglib_U2_U0.so+0x9afff)}}
{{ #5 magazine_cache_pop_magazine glib/gslice.c:723:3 (libglib_U2_U0.so+0x9afff)}}
{{ #6 thread_memory_magazine1_reload glib/gslice.c:806:17 (libglib_U2_U0.so+0x9afff)}}
{{ #7 g_slice_alloc glib/gslice.c:1019:13 (libglib_U2_U0.so+0x9afff)}}
{{ #8 g_hash_table_new_full glib/ghash.c:717:16 (libglib_U2_U0.so+0x51a32)}}
{{ #9 g_hash_table_new glib/ghash.c:680:10 (libglib_U2_U0.so+0x51a32)}}
{{ #10 g_quark_init glib/gquark.c:61:14 (libglib_U2_U0.so+0x86a56)}}
{{ #11 glib_init glib/glib-init.c:273:3 (libglib_U2_U0.so+0x66705)}}
{{ #12 glib_init_ctor glib/glib-init.c:331:3 (libglib_U2_U0.so+0x66731)}}
Thread T721 (tid=6674, running) created by main thread at:
{{ #0 pthread_create tsan_interceptors_posix.cpp (9ee74028fd01cbfaab89acc835454f305a958cd447bb3925200f864cd2887309_020027025bc0+0x77468a)}}
{{ #1 QThread::start(QThread::Priority) qtbase-everywhere-src-5_12_2/src/corelib/thread/qthread_unix.cpp:724:16 (qt_Slibcore.so+0x35ff09)}}
{{ #2 QThreadPoolPrivate::tryStart(QRunnable*) qtbase-everywhere-src-5_12_2/src/corelib/thread/qthreadpool.cpp:199:17 (qt_Slibcore.so+0x361900)}}
{{ #3 QThreadPool::start(QRunnable*, int) qtbase-everywhere-src-5_12_2/src/corelib/thread/qthreadpool.cpp:506:13 (qt_Slibcore.so+0x36322f)}}
{{ #4 start qtbase-everywhere-src-5_12_2/include/QtConcurrent/../../src/concurrent/qtconcurrentrunbase.h:87:15 (.so+0x74a76)}}
{{ #5 start qtbase-everywhere-src-5_12_2/include/QtConcurrent/../../src/concurrent/qtconcurrentrunbase.h:78:16 (.so+0x74a76)}}
{{ #6 run<(lambda)> qtbase-everywhere-src-5_12_2/include/QtConcurrent/../../src/concurrent/qtconcurrentrun.h:108:69 (.so+0x74a76)}}
{{ Thread T934 'Thread (pooled)' (tid=6662, finished) created by main thread at:}}
{{ #0 pthread_create tsan_interceptors_posix.cpp (9ee74028fd01cbfaab89acc835454f305a958cd447bb3925200f864cd2887309_020027025bc0+0x77468a)}}
{{ #1 QThread::start(QThread::Priority) qtbase-everywhere-src-5_12_2/src/corelib/thread/qthread_unix.cpp:724:16 (qt_Slibcore.so+0x35ff09)}}
{{ #2 QThreadPoolPrivate::startThread(QRunnable*) qtbase-everywhere-src-5_12_2/src/corelib/thread/qthreadpool.cpp:275:20 (qt_Slibcore.so+0x361a84)}}
{{ #3 QThreadPoolPrivate::tryStart(QRunnable*) qtbase-everywhere-src-5_12_2/src/corelib/thread/qthreadpool.cpp (qt_Slibcore.so+0x361771)}}
{{ #4 QThreadPool::start(QRunnable*, int) qtbase-everywhere-src-5_12_2/src/corelib/thread/qthreadpool.cpp:506:13 (qt_Slibcore.so+0x36322f)}}
{{ #5 start qtbase-everywhere-src-5_12_2/include/QtConcurrent/../../src/concurrent/qtconcurrentrunbase.h:87:15 (.so+0xb076f)}}
{{ #6 start qtbase-everywhere-src-5_12_2/include/QtConcurrent/../../src/concurrent/qtconcurrentrunbase.h:78:16 (.so+0xb076f)}}
{{ #7 run<(lambda)> qtbase-everywhere-src-5_12_2/include/QtConcurrent/../../src/concurrent/qtconcurrentrun.h:108:69 (.so+0xb076f)}}
SUMMARY: ThreadSanitizer: data race glib/gslice.c in g_mutex_lock_a