Thread race in JuceVSTWrapper::createEditorComp

WARNING: ThreadSanitizer: data race (pid=7335)
Write of size 4 at 0x7b64001248a0 by main thread (mutexes: write M825701810479044344):
#0 JuceVSTWrapper::createEditorComp() juce_VST_Wrapper.cpp:1138 (Analog Rytm:x86_64+0x1c955)
#1 JuceVSTWrapper::handleGetEditorBounds(JuceVSTWrapper::VstOpCodeArguments) juce_VST_Wrapper.cpp:1816 (Analog Rytm:x86_64+0x14e18)
#2 JuceVSTWrapper::dispatcher(int, JuceVSTWrapper::VstOpCodeArguments) juce_VST_Wrapper.cpp:1205 (Analog Rytm:x86_64+0x13241)
#3 JuceVSTWrapper::dispatcherCB(Vst2::AEffect*, int, int, long long, void*, float) juce_VST_Wrapper.cpp:1252 (Analog Rytm:x86_64+0x9f6f)
#4 juce::VSTPluginInstance::dispatch(int, int, long long, void*, float) const juce_VSTPluginFormat.cpp:1751 (pluginval:x86_64+0x1000ae339)
#5 juce::VSTPluginWindow::dispatch(int, int, int, void*, float) juce_VSTPluginFormat.cpp:3279 (pluginval:x86_64+0x100174962)
#6 juce::VSTPluginWindow::VSTPluginWindow(juce::VSTPluginInstance&) juce_VSTPluginFormat.cpp:2798 (pluginval:x86_64+0x100174450)
#7 juce::VSTPluginWindow::VSTPluginWindow(juce::VSTPluginInstance&) juce_VSTPluginFormat.cpp:2772 (pluginval:x86_64+0x1000ac928)
#8 juce::VSTPluginInstance::createEditor() juce_VSTPluginFormat.cpp:3486 (pluginval:x86_64+0x1000ac848)
#9 BackgroundThreadStateTest::runTest(PluginTests&, juce::AudioPluginInstance&)::'lambda'()::operator()() const BasicTests.cpp:415 (pluginval:x86_64+0x100079256)
#10 void std::__1::__invoke_void_return_wrapper<void>::__call<BackgroundThreadStateTest::runTest(PluginTests&, juce::AudioPluginInstance&)::'lambda'()&>(BackgroundThreadStateTest::runTest(PluginTests&, juce::AudioPluginInstance&)::'lambda'()&&&) type_traits:4345 (pluginval:x86_64+0x100079190)
#11 std::__1::__function::__func<BackgroundThreadStateTest::runTest(PluginTests&, juce::AudioPluginInstance&)::'lambda'(), std::__1::allocator<BackgroundThreadStateTest::runTest(PluginTests&, juce::AudioPluginInstance&)::'lambda'()>, void ()>::operator()() functional:1562 (pluginval:x86_64+0x100078fbc)
#12 std::__1::function<void ()>::operator()() const functional:1913 (pluginval:x86_64+0x10006054e)
#13 juce::MessageManager::callAsync(std::__1::function<void ()>)::AsyncCallInvoker::messageCallback() juce_MessageManager.cpp:192 (pluginval:x86_64+0x1008f669c)
#14 juce::MessageQueue::deliverNextMessage() juce_osx_MessageQueue.h:82 (pluginval:x86_64+0x100908ec6)
#15 juce::MessageQueue::runLoopCallback() juce_osx_MessageQueue.h:93 (pluginval:x86_64+0x100908de9)
#16 juce::MessageQueue::runLoopSourceCallback(void*) juce_osx_MessageQueue.h:101 (pluginval:x86_64+0x100908bb8)
#17 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ <null> (CoreFoundation:x86_64h+0x57682)
#18 juce::JUCEApplicationBase::main() juce_ApplicationBase.cpp:262 (pluginval:x86_64+0x1008df20c)
#19 juce::JUCEApplicationBase::main(int, char const**) juce_ApplicationBase.cpp:240 (pluginval:x86_64+0x1008dec05)
#20 main Main.cpp:183 (pluginval:x86_64+0x10001051c)

Previous read of size 4 at 0x7b64001248a0 by thread T8:
#0 juce::VSTPluginInstance::usesChunks() const juce_VSTPluginFormat.cpp:1957 (pluginval:x86_64+0x10018d5c4)
#1 juce::VSTPluginInstance::getChunkData(juce::MemoryBlock&, bool, int) const juce_VSTPluginFormat.cpp:1961 (pluginval:x86_64+0x1000b21f4)
#2 juce::VSTPluginInstance::saveToFXBFile(juce::MemoryBlock&, bool, int) juce_VSTPluginFormat.cpp:1870 (pluginval:x86_64+0x1000b16be)
#3 juce::VSTPluginInstance::getStateInformation(juce::MemoryBlock&) juce_VSTPluginFormat.cpp:1611 (pluginval:x86_64+0x100140a72)
#4 BackgroundThreadStateTest::runTest(PluginTests&, juce::AudioPluginInstance&) BasicTests.cpp:431 (pluginval:x86_64+0x100076876)
#5 PluginTests::testType(juce::PluginDescription const&) PluginTests.cpp:153 (pluginval:x86_64+0x100037182)
#6 PluginTests::runTest() PluginTests.cpp:90 (pluginval:x86_64+0x100035f46)
#7 juce::UnitTest::performTest(juce::UnitTestRunner*) juce_UnitTest.cpp:77 (pluginval:x86_64+0x100790c1d)
#8 juce::UnitTestRunner::runTests(juce::Array<juce::UnitTest*, juce::DummyCriticalSection, 0> const&, long long) juce_UnitTest.cpp:165 (pluginval:x86_64+0x1007920d4)
#9 runTests(PluginTests&, std::__1::function<void (juce::String const&)>) Validator.cpp:106 (pluginval:x86_64+0x1000580b7)
#10 validate(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String const&)>) Validator.cpp:123 (pluginval:x86_64+0x100057821)
#11 ValidatorSlaveProcess::processRequest(juce::MemoryBlock) Validator.cpp:383 (pluginval:x86_64+0x100055858)
#12 ValidatorSlaveProcess::processRequests() Validator.cpp:352 (pluginval:x86_64+0x100054562)
#13 ValidatorSlaveProcess::run() Validator.cpp:319 (pluginval:x86_64+0x100051152)
#14 non-virtual thunk to ValidatorSlaveProcess::run() Validator.cpp (pluginval:x86_64+0x10005138c)
#15 juce::Thread::threadEntryPoint() juce_Thread.cpp:96 (pluginval:x86_64+0x10078375c)
#16 juce::juce_threadEntryPoint(void*) juce_Thread.cpp:118 (pluginval:x86_64+0x100783f78)
#17 juce::threadEntryProc(void*) juce_posix_SharedCode.h:896 (pluginval:x86_64+0x1007d80b9)

Location is heap block of size 1184 at 0x7b6400124800 allocated by main thread:
#0 operator new(unsigned long) <null> (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x4ec7b)
#1 (anonymous namespace)::pluginEntryPoint(long long (*)(Vst2::AEffect*, int, int, long long, void*, float)) juce_VST_Wrapper.cpp:2341 (Analog Rytm:x86_64+0x7c24)
#2 main_macho juce_VST_Wrapper.cpp:2386 (Analog Rytm:x86_64+0x7eec)
#3 juce::VSTPluginInstance::constructEffect(juce::ReferenceCountedObjectPtr<juce::ModuleHandle> const&) juce_VSTPluginFormat.cpp:2175 (pluginval:x86_64+0x10017868c)
#4 juce::VSTPluginInstance::create(juce::ReferenceCountedObjectPtr<juce::ModuleHandle> const&, double, int) juce_VSTPluginFormat.cpp:1165 (pluginval:x86_64+0x1000af983)
#5 juce::VSTPluginFormat::createPluginInstance(juce::PluginDescription const&, double, int, std::__1::function<void (std::__1::unique_ptr<juce::AudioPluginInstance, std::__1::default_delete<juce::AudioPluginInstance> >, juce::String const&)>) juce_VSTPluginFormat.cpp:3597 (pluginval:x86_64+0x1000ae7da)
#6 juce::AudioPluginFormat::handleMessage(juce::Message const&) juce_AudioPluginFormat.cpp:96 (pluginval:x86_64+0x100086e4f)
#7 juce::Message::messageCallback() juce_MessageListener.cpp:32 (pluginval:x86_64+0x1008e07a1)
#8 juce::MessageQueue::deliverNextMessage() juce_osx_MessageQueue.h:82 (pluginval:x86_64+0x100908ec6)
#9 juce::MessageQueue::runLoopCallback() juce_osx_MessageQueue.h:93 (pluginval:x86_64+0x100908de9)
#10 juce::MessageQueue::runLoopSourceCallback(void*) juce_osx_MessageQueue.h:101 (pluginval:x86_64+0x100908bb8)
#11 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ <null> (CoreFoundation:x86_64h+0x57682)
#12 juce::JUCEApplicationBase::main() juce_ApplicationBase.cpp:262 (pluginval:x86_64+0x1008df20c)
#13 juce::JUCEApplicationBase::main(int, char const**) juce_ApplicationBase.cpp:240 (pluginval:x86_64+0x1008dec05)
#14 main Main.cpp:183 (pluginval:x86_64+0x10001051c)

  Mutex M825701810479044344 is already destroyed.

 Thread T8 (tid=49897, running) created by main thread at:
#0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x89dd)
#1 juce::Thread::launchThread() juce_posix_SharedCode.h:953 (pluginval:x86_64+0x1007841b9)
#2 juce::Thread::startThread() juce_Thread.cpp:130 (pluginval:x86_64+0x100784028)
#3 juce::Thread::startThread(int) juce_Thread.cpp:152 (pluginval:x86_64+0x1007844fb)
#4 ValidatorSlaveProcess::ValidatorSlaveProcess() Validator.cpp:201 (pluginval:x86_64+0x100050c61)
#5 ValidatorSlaveProcess::ValidatorSlaveProcess() Validator.cpp:196 (pluginval:x86_64+0x100050798)
#6 ValidatorMasterProcess::launchInProcess() memory:3114 (pluginval:x86_64+0x10004d11c)
#7 Validator::ensureConnection() Validator.cpp:640 (pluginval:x86_64+0x10004b787)
#8 Validator::validate(juce::StringArray const&, PluginTests::Options) Validator.cpp:592 (pluginval:x86_64+0x10004adb5)
#9 CommandLineValidator::validate(juce::StringArray const&, PluginTests::Options, bool) CommandLine.cpp:102 (pluginval:x86_64+0x100008d04)
#10 validate(CommandLineValidator&, juce::StringArray const&) CommandLine.cpp:270 (pluginval:x86_64+0x10000c871)
#11 performCommandLine(CommandLineValidator&, juce::String const&) CommandLine.cpp:410 (pluginval:x86_64+0x10000b2f7)
#12 PluginValidatorApplication::handleAsyncUpdate() Main.cpp:177 (pluginval:x86_64+0x1000132e7)
#13 non-virtual thunk to PluginValidatorApplication::handleAsyncUpdate() Main.cpp (pluginval:x86_64+0x1000134ac)
#14 juce::AsyncUpdater::AsyncUpdaterMessage::messageCallback() juce_AsyncUpdater.cpp:34 (pluginval:x86_64+0x1008f89e3)
#15 juce::MessageQueue::deliverNextMessage() juce_osx_MessageQueue.h:82 (pluginval:x86_64+0x100908ec6)
#16 juce::MessageQueue::runLoopCallback() juce_osx_MessageQueue.h:93 (pluginval:x86_64+0x100908de9)
#17 juce::MessageQueue::runLoopSourceCallback(void*) juce_osx_MessageQueue.h:101 (pluginval:x86_64+0x100908bb8)
#18 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ <null> (CoreFoundation:x86_64h+0x57682)
#19 juce::JUCEApplicationBase::main() juce_ApplicationBase.cpp:262 (pluginval:x86_64+0x1008df20c)
#20 juce::JUCEApplicationBase::main(int, char const**) juce_ApplicationBase.cpp:240 (pluginval:x86_64+0x1008dec05)
#21 main Main.cpp:183 (pluginval:x86_64+0x10001051c)

SUMMARY: ThreadSanitizer: data race juce_VST_Wrapper.cpp:1138 in JuceVSTWrapper::createEditorComp()

bump :slight_smile:

I’m afraid I’m struggling to reproduce this, and it’s not clear from your sanitizer trace exactly what the race is…

It looks like it is vstEffect.flags that are accessed from two threads.

image
image

Thank you.

1 Like

Thread sanitizer still reports that there is a race. I guess it is setting the flag in createEditorComp()

 vstEffect.flags = vstEffectAtomicFlags;

and then reading it in usesChunks() that is what thread sanitizer complains about. The flags member is an int32_t. That should be possibe to read and write atomically on x86, right?

If so maybe this is not a big problem, but it would be nice to get rid of the warning so that it is possible to run thread sanitizer in this context, and with that one could catch other problems. It is difficult to catch real issues in automation if there is a warning like this which is not silenced.

One possibility could be to use an attribute on those two functions. https://chromium.googlesource.com/external/llvm.org/clang/+/google/stable/docs/ThreadSanitizer.rst#96

#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define JUCE_NO_THREAD_SANITIZER __attribute__((no_sanitize("thread")))
#else
#define JUCE_NO_THREAD_SANITIZER
#endif
#else
#define JUCE_NO_THREAD_SANITIZER
#endif
1 Like

OK, I’ve had another attempt:

If tsan is still getting triggered then we’ll look at suppressing the sanitiser.

Warning is gone now. Great!