I post it here because I don’t know whether it is a pluginval/JUCE/my issue.
Environment:
- Github Runner Image macOS 15.1 Arm64 & AppleClang 16.0.0.16000026
- Test repo JUCE version: 8.0.4
- pluginval JUCE version: 8.0.3
- How to reproduce: Build the test repo and the pluginval with Thread Sanitizer. Run pluginval to test the AU format.
The test repo is here:
It is very simple. Every 4800 samples it changes the plugin latency via async call:
void PluginProcessor::processBlock(juce::AudioBuffer<float> &buffer,
juce::MidiBuffer &midiMessages) {
// clear unused buffer here
sampleNum += buffer.getNumSamples();
if (sampleNum >= 4800) {
sampleNum = 0;
latency.store(10 - latency.load());
triggerAsyncUpdate();
}
}
void handleAsyncUpdate() override {
setLatencySamples(latency.load());
}
And the error given by the action is:
WARNING: ThreadSanitizer: data race (pid=7800)
Write of size 4 at 0x00010930f03c by main thread:
#0 juce::AudioProcessor::setLatencySamples(int) juce_AudioProcessor.cpp:419 (ZL Test:arm64+0xd5cc4)
#1 PluginProcessor::handleAsyncUpdate() PluginProcessor.h:58 (ZL Test:arm64+0x1134d8c)
#2 non-virtual thunk to PluginProcessor::handleAsyncUpdate() PluginProcessor.h (ZL Test:arm64+0x1134de4)
#3 juce::AsyncUpdater::AsyncUpdaterMessage::messageCallback() juce_AsyncUpdater.cpp:46 (ZL Test:arm64+0xe8c5a8)
#4 juce::MessageQueue::deliverNextMessage() juce_MessageQueue_mac.h:93 (ZL Test:arm64+0xebe5a0)
#5 juce::MessageQueue::runLoopCallback() juce_MessageQueue_mac.h:104 (ZL Test:arm64+0xebe4d0)
#6 juce::MessageQueue::runLoopSourceCallback(void*) juce_MessageQueue_mac.h:112 (ZL Test:arm64+0xebdf9c)
#7 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ <null>:123738768 (CoreFoundation:arm64e+0x7dd30)
#8 juce::JUCEApplicationBase::main() juce_ApplicationBase.cpp:277 (pluginval:arm64+0x100556940)
#9 juce::JUCEApplicationBase::main(int, char const**) juce_ApplicationBase.cpp:255 (pluginval:arm64+0x1005566e4)
#10 main Main.cpp:173 (pluginval:arm64+0x100040010)
Previous read of size 4 at 0x00010930f03c by thread T5:
#0 juce::AudioProcessor::getLatencySamples() const juce_AudioProcessor.h:843 (ZL Test:arm64+0x7c734)
#1 JuceAU::GetLatency() juce_audio_plugin_client_AU_1.mm:1207 (ZL Test:arm64+0x125f4)
#2 ausdk::AUBase::DispatchGetProperty(unsigned int, unsigned int, unsigned int, void*) AUBase.cpp:543 (ZL Test:arm64+0x8a2bc)
#3 ausdk::AUMethodGetProperty(void*, unsigned int, unsigned int, unsigned int, void*, unsigned int*) AUPlugInDispatch.cpp:157 (ZL Test:arm64+0x9d224)
#4 AudioUnitGetProperty <null>:126877984 (AudioToolboxCore:arm64e+0x2cffb0)
#5 juce::AudioUnitPluginInstance::prepareToPlay(double, int)::'lambda'()::operator()() const juce_AudioUnitPluginFormat.mm:1297 (pluginval:arm64+0x1008ffc04)
#6 juce::AudioUnitPluginInstance::prepareToPlay(double, int) juce_AudioUnitPluginFormat.mm:1283 (pluginval:arm64+0x1006a7f6c)
#7 callPrepareToPlayOnMessageThreadIfVST3(juce::AudioPluginInstance&, double, int) TestUtilities.h:201 (pluginval:arm64+0x100094e28)
#8 AudioProcessingTest::runAudioProcessingTest(PluginTests&, juce::AudioPluginInstance&, bool) BasicTests.cpp:197 (pluginval:arm64+0x1000a0944)
#9 AudioProcessingTest::runTest(PluginTests&, juce::AudioPluginInstance&) BasicTests.cpp:246 (pluginval:arm64+0x1000a079c)
#10 PluginTests::testType(juce::PluginDescription const&) PluginTests.cpp:210 (pluginval:arm64+0x10007d700)
#11 PluginTests::runTest() PluginTests.cpp:125 (pluginval:arm64+0x10007cae4)
#12 juce::UnitTest::performTest(juce::UnitTestRunner*) juce_UnitTest.cpp:89 (pluginval:arm64+0x1002b7b10)
#13 juce::UnitTestRunner::runTests(juce::Array<juce::UnitTest*, juce::DummyCriticalSection, 0> const&, long long) juce_UnitTest.cpp:177 (pluginval:arm64+0x1002b8e28)
#14 runTests(PluginTests&, std::__1::function<void (juce::String const&)>) Validator.cpp:198 (pluginval:arm64+0x1000d2364)
#15 validate(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String const&)>) Validator.cpp:216 (pluginval:arm64+0x1000ce138)
#16 AsyncValidator::run() Validator.cpp:379 (pluginval:arm64+0x1000cdd38)
#17 AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>)::'lambda'()::operator()() const Validator.cpp:343 (pluginval:arm64+0x1000cdc48)
#18 decltype(std::declval<AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>)::'lambda'()>()()) std::__1::__invoke[abi:ne180100]<AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>)::'lambda'()>(AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>)::'lambda'()&&) invoke.h:344 (pluginval:arm64+0x1000cdb98)
#19 void std::__1::__thread_execute[abi:ne180100]<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>)::'lambda'()>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>)::'lambda'()>&, std::__1::__tuple_indices<>) thread.h:199 (pluginval:arm64+0x1000cdb44)
#20 void* std::__1::__thread_proxy[abi:ne180100]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>)::'lambda'()>>(void*) thread.h:208 (pluginval:arm64+0x1000cd5d8)
Location is heap block of size 624 at 0x00010930f000 allocated by main thread:
#0 operator new(unsigned long) <null>:131081760 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x84210)
#1 createPluginFilter() PluginProcessor.cpp:173 (ZL Test:arm64+0x1134ccc)
#2 juce::createPluginFilterOfType(juce::AudioProcessor::WrapperType) juce_CreatePluginFilter.h:44 (ZL Test:arm64+0x14234)
#3 AudioProcessorHolder::AudioProcessorHolder() juce_audio_plugin_client_AU_1.mm:126 (ZL Test:arm64+0xb8e0)
#4 JuceAU::JuceAU(ComponentInstanceRecord*) juce_audio_plugin_client_AU_1.mm:150 (ZL Test:arm64+0xb144)
#5 JuceAU::JuceAU(ComponentInstanceRecord*) juce_audio_plugin_client_AU_1.mm:154 (ZL Test:arm64+0xb0cc)
#6 ausdk::APFactory<ausdk::AUBaseLookup, JuceAU>::Construct(void*, ComponentInstanceRecord*) ComponentBase.h:108 (ZL Test:arm64+0xb000)
#7 ausdk::ComponentBase::AP_Open(void*, ComponentInstanceRecord*) ComponentBase.cpp:48 (ZL Test:arm64+0xa35f0)
#8 APComponent::newInstance(unsigned int, bool, void (OpaqueAudioComponentInstance*, int) block_pointer) <null>:126880192 (AudioToolboxCore:arm64e+0x1047b0)
#9 juce::AudioUnitPluginFormat::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_AudioUnitPluginFormat.mm:2804 (pluginval:arm64+0x10067ffcc)
#10 juce::AudioPluginFormat::handleMessage(juce::Message const&) juce_AudioPluginFormat.cpp:104 (pluginval:arm64+0x100605eb8)
#11 juce::Message::messageCallback() juce_MessageListener.cpp:44 (pluginval:arm64+0x100557b3c)
#12 juce::MessageQueue::deliverNextMessage() juce_MessageQueue_mac.h:93 (pluginval:arm64+0x100597b20)
#13 juce::MessageQueue::runLoopCallback() juce_MessageQueue_mac.h:104 (pluginval:arm64+0x100597a50)
#14 juce::MessageQueue::runLoopSourceCallback(void*) juce_MessageQueue_mac.h:112 (pluginval:arm64+0x10059751c)
#15 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ <null>:123733808 (CoreFoundation:arm64e+0x7dd30)
#16 juce::JUCEApplicationBase::main() juce_ApplicationBase.cpp:277 (pluginval:arm64+0x100556940)
#17 juce::JUCEApplicationBase::main(int, char const**) juce_ApplicationBase.cpp:255 (pluginval:arm64+0x1005566e4)
#18 main Main.cpp:173 (pluginval:arm64+0x100040010)
Thread T5 (tid=30200, running) created by main thread at:
#0 pthread_create <null>:131081760 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x309d8)
#1 std::__1::__libcpp_thread_create[abi:ne180100](_opaque_pthread_t**, void* (*)(void*), void*) __threading_support:317 (pluginval:arm64+0x10009dd84)
#2 std::__1::thread::thread<AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>)::'lambda'(), void>(AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>)::'lambda'()&&) thread.h:218 (pluginval:arm64+0x1000cd3bc)
#3 std::__1::thread::thread<AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>)::'lambda'(), void>(AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>)::'lambda'()&&) thread.h:213 (pluginval:arm64+0x1000cceb8)
#4 AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>) Validator.cpp:343 (pluginval:arm64+0x1000cccd0)
#5 AsyncValidator::AsyncValidator(juce::String const&, PluginTests::Options, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>) Validator.cpp:342 (pluginval:arm64+0x1000cc41c)
#6 std::__1::__unique_if<AsyncValidator>::__unique_single std::__1::make_unique[abi:ne180100]<AsyncValidator, juce::String const&, PluginTests::Options&, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>>(juce::String const&, PluginTests::Options&, std::__1::function<void (juce::String)>&&, std::__1::function<void (juce::String, unsigned int)>&&, std::__1::function<void (juce::String const&)>&&) unique_ptr.h:597 (pluginval:arm64+0x1000c906c)
#7 ValidationPass::ValidationPass(juce::String const&, PluginTests::Options, ValidationType, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>) Validator.cpp:404 (pluginval:arm64+0x1000c8df8)
#8 ValidationPass::ValidationPass(juce::String const&, PluginTests::Options, ValidationType, std::__1::function<void (juce::String)>, std::__1::function<void (juce::String, unsigned int)>, std::__1::function<void (juce::String const&)>) Validator.cpp:401 (pluginval:arm64+0x1000c95a0)
#9 std::__1::__unique_if<ValidationPass>::__unique_single std::__1::make_unique[abi:ne180100]<ValidationPass, juce::String const&, PluginTests::Options&, ValidationType, CommandLineValidator::validate(juce::String const&, PluginTests::Options)::$_0, CommandLineValidator::validate(juce::String const&, PluginTests::Options)::$_1, CommandLineValidator::validate(juce::String const&, PluginTests::Options)::$_2>(juce::String const&, PluginTests::Options&, ValidationType&&, CommandLineValidator::validate(juce::String const&, PluginTests::Options)::$_0&&, CommandLineValidator::validate(juce::String const&, PluginTests::Options)::$_1&&, CommandLineValidator::validate(juce::String const&, PluginTests::Options)::$_2&&) unique_ptr.h:597 (pluginval:arm64+0x10000c308)
#10 CommandLineValidator::validate(juce::String const&, PluginTests::Options) CommandLine.cpp:98 (pluginval:arm64+0x10000c1b4)
#11 _ZZL18performCommandLineR20CommandLineValidatorRKN4juce12ArgumentListEENK3$_0clIS2_EEDaRKT_ CommandLine.cpp:495 (pluginval:arm64+0x1000147c4)
#12 decltype(std::declval<performCommandLine(CommandLineValidator&, juce::ArgumentList const&)::$_0&>()(std::declval<juce::ArgumentList const&>())) std::__1::__invoke[abi:ne180100]<performCommandLine(CommandLineValidator&, juce::ArgumentList const&)::$_0&, juce::ArgumentList const&>(performCommandLine(CommandLineValidator&, juce::ArgumentList const&)::$_0&, juce::ArgumentList const&) invoke.h:344 (pluginval:arm64+0x1000146d8)
#13 void std::__1::__invoke_void_return_wrapper<void, true>::__call[abi:ne180100]<performCommandLine(CommandLineValidator&, juce::ArgumentList const&)::$_0&, juce::ArgumentList const&>(performCommandLine(CommandLineValidator&, juce::ArgumentList const&)::$_0&, juce::ArgumentList const&) invoke.h:419 (pluginval:arm64+0x10001462c)
#14 std::__1::__function::__alloc_func<performCommandLine(CommandLineValidator&, juce::ArgumentList const&)::$_0, std::__1::allocator<performCommandLine(CommandLineValidator&, juce::ArgumentList const&)::$_0>, void (juce::ArgumentList const&)>::operator()[abi:ne180100](juce::ArgumentList const&) function.h:169 (pluginval:arm64+0x1000145c8)
#15 std::__1::__function::__func<performCommandLine(CommandLineValidator&, juce::ArgumentList const&)::$_0, std::__1::allocator<performCommandLine(CommandLineValidator&, juce::ArgumentList const&)::$_0>, void (juce::ArgumentList const&)>::operator()(juce::ArgumentList const&) function.h:311 (pluginval:arm64+0x100012294)
#16 std::__1::__function::__value_func<void (juce::ArgumentList const&)>::operator()[abi:ne180100](juce::ArgumentList const&) const function.h:428 (pluginval:arm64+0x100471560)
#17 std::__1::function<void (juce::ArgumentList const&)>::operator()(juce::ArgumentList const&) const function.h:981 (pluginval:arm64+0x10047149c)
#18 juce::ConsoleApplication::findAndRunCommand(juce::ArgumentList const&, bool) const::$_0::operator()() const juce_ConsoleApplication.cpp:351 (pluginval:arm64+0x1004713cc)
#19 decltype(std::declval<juce::ConsoleApplication::findAndRunCommand(juce::ArgumentList const&, bool) const::$_0&>()()) std::__1::__invoke[abi:ne180100]<juce::ConsoleApplication::findAndRunCommand(juce::ArgumentList const&, bool) const::$_0&>(juce::ConsoleApplication::findAndRunCommand(juce::ArgumentList const&, bool) const::$_0&) invoke.h:344 (pluginval:arm64+0x1004712e4)
#20 int std::__1::__invoke_void_return_wrapper<int, false>::__call[abi:ne180100]<juce::ConsoleApplication::findAndRunCommand(juce::ArgumentList const&, bool) const::$_0&>(juce::ConsoleApplication::findAndRunCommand(juce::ArgumentList const&, bool) const::$_0&) invoke.h:411 (pluginval:arm64+0x100471240)
#21 std::__1::__function::__alloc_func<juce::ConsoleApplication::findAndRunCommand(juce::ArgumentList const&, bool) const::$_0, std::__1::allocator<juce::ConsoleApplication::findAndRunCommand(juce::ArgumentList const&, bool) const::$_0>, int ()>::operator()[abi:ne180100]() function.h:169 (pluginval:arm64+0x1004711e4)
#22 std::__1::__function::__func<juce::ConsoleApplication::findAndRunCommand(juce::ArgumentList const&, bool) const::$_0, std::__1::allocator<juce::ConsoleApplication::findAndRunCommand(juce::ArgumentList const&, bool) const::$_0>, int ()>::operator()() function.h:311 (pluginval:arm64+0x10046f498)
#23 std::__1::__function::__value_func<int ()>::operator()[abi:ne180100]() const function.h:428 (pluginval:arm64+0x10046e3c8)
#24 std::__1::function<int ()>::operator()() const function.h:981 (pluginval:arm64+0x10027f1e4)
#25 juce::ConsoleApplication::invokeCatchingFailures(std::__1::function<int ()>&&) juce_ConsoleApplication.cpp:319 (pluginval:arm64+0x10027f0b0)
#26 juce::ConsoleApplication::findAndRunCommand(juce::ArgumentList const&, bool) const juce_ConsoleApplication.cpp:348 (pluginval:arm64+0x10027f668)
#27 performCommandLine(CommandLineValidator&, juce::ArgumentList const&) CommandLine.cpp:502 (pluginval:arm64+0x10000c7ac)
#28 performCommandLine(CommandLineValidator&, juce::String const&) CommandLine.cpp:516 (pluginval:arm64+0x10000c528)
#29 PluginValidatorApplication::handleAsyncUpdate() Main.cpp:167 (pluginval:arm64+0x100040a64)
#30 non-virtual thunk to PluginValidatorApplication::handleAsyncUpdate() Main.cpp (pluginval:arm64+0x100040c20)
#31 juce::AsyncUpdater::AsyncUpdaterMessage::messageCallback() juce_AsyncUpdater.cpp:46 (pluginval:arm64+0x10056b8f8)
#32 juce::MessageQueue::deliverNextMessage() juce_MessageQueue_mac.h:93 (pluginval:arm64+0x100597b20)
#33 juce::MessageQueue::runLoopCallback() juce_MessageQueue_mac.h:104 (pluginval:arm64+0x100597a50)
#34 juce::MessageQueue::runLoopSourceCallback(void*) juce_MessageQueue_mac.h:112 (pluginval:arm64+0x10059751c)
#35 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ <null>:123746688 (CoreFoundation:arm64e+0x7dd30)
#36 juce::JUCEApplicationBase::main() juce_ApplicationBase.cpp:277 (pluginval:arm64+0x100556940)
#37 juce::JUCEApplicationBase::main(int, char const**) juce_ApplicationBase.cpp:255 (pluginval:arm64+0x1005566e4)
#38 main Main.cpp:173 (pluginval:arm64+0x100040010)
SUMMARY: ThreadSanitizer: data race juce_AudioProcessor.cpp:419 in juce::AudioProcessor::setLatencySamples(int)
AFAICT, it is because of the race of the variable latencySamples. Did I do something wrong? Is it correct to call setLatencySamples() on the message thread?
