Data race in `juce_audio_devices` on Linux ALSA

Problem

When running a standalone plugin build on Linux with TSAN enabled, it reports the following summary:

SUMMARY: ThreadSanitizer: data race ../3rd_party/JUCE/modules/juce_audio_devices/native/juce_linux_ALSA.cpp:712 in run
==================
ThreadSanitizer: reported 4 warnings

It seems that the member numCallbacks should be protected by a lock, since one line above a lock is instantiated:

const ScopedLock sl (callbackLock);
++numCallbacks;

More output from TSAN reveals the issue:

WARNING: ThreadSanitizer: data race (pid=354357)
  Write of size 4 at 0x7b6800000868 by thread T5 (mutexes: write M1012):
    #0 run ../3rd_party/JUCE/modules/juce_audio_devices/native/juce_linux_ALSA.cpp:712 (MyPlugin+0x9c6e9)
    #1 juce::Thread::threadEntryPoint() ../3rd_party/JUCE/modules/juce_core/threads/juce_Thread.cpp:96 (MyPlugin+0xc7e71)
    #2 juce::juce_threadEntryPoint(void*) ../3rd_party/JUCE/modules/juce_core/threads/juce_Thread.cpp:118 (MyPlugin+0xc7e71)
    #3 threadEntryProc ../3rd_party/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:838 (MyPlugin+0xc7e71)
    #4 <null> <null> (libtsan.so.0+0x2d1af)

  Previous read of size 4 at 0x7b6800000868 by main thread:
    #0 open ../3rd_party/JUCE/modules/juce_audio_devices/native/juce_linux_ALSA.cpp:627 (MyPlugin+0x96c7f)
    #1 open ../3rd_party/JUCE/modules/juce_audio_devices/native/juce_linux_ALSA.cpp:909 (MyPlugin+0x96c7f)

The main thread is reading numCallbacks without a lock while the ALSA thread is already running.

Possible Solution

I replaced the definition of int numCallback with std::atomic<int> numCallbacks and adapted the usage. Only 5 lines. TSAN was happy afterwards.

Thanks for reporting!

1 Like