Thread sanitizer warning in juce::OpenGLContext::CachedImage::updateViewportSize

Looks like variable scale is both used and assigned to on row 249 and 294 in juce_OpenGLContext.cpp.

 SUMMARY: ThreadSanitizer: data race juce_OpenGLContext.cpp:294 in juce::OpenGLContext::CachedImage::updateViewportSize(bool)
    ==================
    ==================
    WARNING: ThreadSanitizer: data race (pid=14390)
      Read of size 8 at 0x7b600000c4e0 by thread T35 (mutexes: write M388008445032455848):
        #0 juce::OpenGLContext::CachedImage::renderFrame() juce_OpenGLContext.cpp:249 (MyPlugin:x86_64+0x18bc77e)
        #1 juce::OpenGLContext::CachedImage::runJob() juce_OpenGLContext.cpp:465 (MyPlugin:x86_64+0x18b6880)
        #2 non-virtual thunk to juce::OpenGLContext::CachedImage::runJob() juce_OpenGLContext.cpp (MyPlugin:x86_64+0x18b6a6f)
        #3 juce::ThreadPool::runNextJob(juce::ThreadPool::ThreadPoolThread&) juce_ThreadPool.cpp:384 (MyPlugin:x86_64+0x14668a1)
        #4 juce::ThreadPool::ThreadPoolThread::run() juce_ThreadPool.cpp:36 (MyPlugin:x86_64+0x14dcae7)
        #5 juce::Thread::threadEntryPoint() juce_Thread.cpp:96 (MyPlugin:x86_64+0x1461ac9)
        #6 juce::juce_threadEntryPoint(void*) juce_Thread.cpp:118 (MyPlugin:x86_64+0x14621c8)
        #7 juce::threadEntryProc(void*) juce_posix_SharedCode.h:896 (MyPlugin:x86_64+0x14b1879)

  Previous write of size 8 at 0x7b600000c4e0 by main thread (mutexes: write M1082688395496394928, write M325521000202657448):
    #0 juce::OpenGLContext::CachedImage::updateViewportSize(bool) juce_OpenGLContext.cpp:294 (MyPlugin:x86_64+0x18bbe79)
    #1 juce::OpenGLContext::CachedImage::paint(juce::Graphics&) juce_OpenGLContext.cpp:148 (MyPlugin:x86_64+0x18b6546)
    #2 juce::Component::paintWithinParentContext(juce::Graphics&) juce_Component.cpp:1887 (MyPlugin:x86_64+0x4543e5)
    #3 juce::Component::paintComponentAndChildren(juce::Graphics&) juce_Component.cpp:1950 (MyPlugin:x86_64+0x455009)
    #4 juce::Component::paintEntireComponent(juce::Graphics&, bool) juce_Component.cpp:2008 (MyPlugin:x86_64+0x4548ee)
    #5 juce::Component::paintWithinParentContext(juce::Graphics&) juce_Component.cpp:1889 (MyPlugin:x86_64+0x4543fe)
    #6 juce::Component::paintComponentAndChildren(juce::Graphics&) juce_Component.cpp:1950 (MyPlugin:x86_64+0x455009)
    #7 juce::Component::paintEntireComponent(juce::Graphics&, bool) juce_Component.cpp:2008 (MyPlugin:x86_64+0x4548ee)
    #8 juce::Component::paintWithinParentContext(juce::Graphics&) juce_Component.cpp:1889 (MyPlugin:x86_64+0x4543fe)
    #9 juce::Component::paintComponentAndChildren(juce::Graphics&) juce_Component.cpp:1950 (MyPlugin:x86_64+0x455009)
    #10 juce::Component::paintEntireComponent(juce::Graphics&, bool) juce_Component.cpp:2008 (MyPlugin:x86_64+0x4548ee)
    #11 juce::Component::paintWithinParentContext(juce::Graphics&) juce_Component.cpp:1889 (MyPlugin:x86_64+0x4543fe)
    #12 juce::Component::paintComponentAndChildren(juce::Graphics&) juce_Component.cpp:1950 (MyPlugin:x86_64+0x455009)
    #13 juce::Component::paintEntireComponent(juce::Graphics&, bool) juce_Component.cpp:2008 (MyPlugin:x86_64+0x4548ee)
    #14 juce::Component::paintWithinParentContext(juce::Graphics&) juce_Component.cpp:1889 (MyPlugin:x86_64+0x4543fe)
    #15 juce::Component::paintComponentAndChildren(juce::Graphics&) juce_Component.cpp:1950 (MyPlugin:x86_64+0x455009)
    #16 juce::Component::paintEntireComponent(juce::Graphics&, bool) juce_Component.cpp:2008 (MyPlugin:x86_64+0x4548ee)
    #17 juce::Component::paintWithinParentContext(juce::Graphics&) juce_Component.cpp:1889 (MyPlugin:x86_64+0x4543fe)
    #18 juce::Component::paintComponentAndChildren(juce::Graphics&) juce_Component.cpp:1950 (MyPlugin:x86_64+0x455009)
    #19 juce::Component::paintEntireComponent(juce::Graphics&, bool) juce_Component.cpp:2008 (MyPlugin:x86_64+0x4548ee)
    #20 juce::Component::paintWithinParentContext(juce::Graphics&) juce_Component.cpp:1889 (MyPlugin:x86_64+0x4543fe)
    #21 juce::Component::paintComponentAndChildren(juce::Graphics&) juce_Component.cpp:1950 (MyPlugin:x86_64+0x455009)
    #22 juce::Component::paintEntireComponent(juce::Graphics&, bool) juce_Component.cpp:2008 (MyPlugin:x86_64+0x4548ee)
    #23 juce::Component::paintWithinParentContext(juce::Graphics&) juce_Component.cpp:1889 (MyPlugin:x86_64+0x4543fe)
    #24 juce::Component::paintComponentAndChildren(juce::Graphics&) juce_Component.cpp:1950 (MyPlugin:x86_64+0x455009)
    #25 juce::Component::paintEntireComponent(juce::Graphics&, bool) juce_Component.cpp:2008 (MyPlugin:x86_64+0x4548ee)
    #26 juce::OpenGLContext::CachedImage::paintOwner(juce::LowLevelGraphicsContext&) juce_OpenGLContext.cpp:393 (MyPlugin:x86_64+0x18bf54c)
    #27 juce::OpenGLContext::CachedImage::paintComponent() juce_OpenGLContext.cpp:342 (MyPlugin:x86_64+0x18bda6e)
    #28 juce::OpenGLContext::CachedImage::renderFrame() juce_OpenGLContext.cpp:260 (MyPlugin:x86_64+0x18bc8bd)
    #29 juce::OpenGLContext::CachedImage::handleResize() juce_OpenGLContext.cpp:423 (MyPlugin:x86_64+0x18bfbbc)
    #30 juce::OpenGLContext::Attachment::componentMovedOrResized(bool, bool) juce_OpenGLContext.cpp:698 (MyPlugin:x86_64+0x18b534c)
    #31 juce::ComponentMovementWatcher::componentMovedOrResized(juce::Component&, bool, bool) juce_ComponentMovementWatcher.cpp:100 (MyPlugin:x86_64+0x4b51f4)
    #32 juce::Component::sendMovedResizedMessages(bool, bool)::$_3::operator()(juce::ComponentListener&) const juce_Component.cpp:1167 (MyPlugin:x86_64+0x6ebce0)
    #33 void juce::ListenerList<juce::ComponentListener, juce::Array<juce::ComponentListener*, juce::DummyCriticalSection, 0> >::callChecked<juce::Component::sendMovedResizedMessages(bool, bool)::$_3, juce::Component::BailOutChecker>(juce::Component::BailOutChecker const&, juce::Component::sendMovedResizedMessages(bool, bool)::$_3&&) juce_ListenerList.h:153 (MyPlugin:x86_64+0x44ceca)
    #34 juce::Component::sendMovedResizedMessages(bool, bool) juce_Component.cpp:1167 (MyPlugin:x86_64+0x44cdb5)
    #35 juce::Component::sendMovedResizedMessagesIfPending() juce_Component.cpp:1129 (MyPlugin:x86_64+0x44cb10)
    #36 juce::Component::setBounds(int, int, int, int) juce_Component.cpp:1115 (MyPlugin:x86_64+0x44c823)
    #37 juce::Component::setTopLeftPosition(juce::Point<int>) juce_Component.cpp:1173 (MyPlugin:x86_64+0x448fba)
    #38 juce::Component::setTopLeftPosition(int, int) juce_Component.cpp:1172 (MyPlugin:x86_64+0x44cfe8)
    #39 JuceVSTWrapper::EditorCompWrapper::updateWindowSize(bool) juce_VST_Wrapper.cpp:1435 (MyPlugin:x86_64+0x201c4)
    #40 JuceVSTWrapper::EditorCompWrapper::childBoundsChanged(juce::Component*) juce_VST_Wrapper.cpp:1413 (MyPlugin:x86_64+0x1d866)
    #41 juce::Component::sendMovedResizedMessages(bool, bool) juce_Component.cpp:1164 (MyPlugin:x86_64+0x44cd66)
    #42 juce::Component::sendMovedResizedMessagesIfPending() juce_Component.cpp:1129 (MyPlugin:x86_64+0x44cb10)
    #43 juce::Component::setBounds(int, int, int, int) juce_Component.cpp:1115 (MyPlugin:x86_64+0x44c823)
    #44 juce::Component::setSize(int, int) juce_Component.cpp:1170 (MyPlugin:x86_64+0x44cf5f)
    #45 PluginAudioProcessorEditor::updateScaleAndSize() PluginAudioProcessorEditor.cpp:225 (MyPlugin:x86_64+0x8c8b0)
    #46 PluginAudioProcessorEditor::changeListenerCallback(SafeChangeBroadcaster*) PluginAudioProcessorEditor.cpp:209 (MyPlugin:x86_64+0x8c6c0)
    #47 non-virtual thunk to PluginAudioProcessorEditor::changeListenerCallback(SafeChangeBroadcaster*) PluginAudioProcessorEditor.cpp (MyPlugin:x86_64+0x8c932)
    #48 SafeChangeBroadcaster::sendSynchronousChangeMessage(juce::Identifier const&) SafeChangeBroadcaster.h:65 (MyPlugin:x86_64+0x9f9c1d)
    #49 SafeChangeBroadcaster::AsyncBroadcaster::handleAsyncUpdate() SafeChangeBroadcaster.h:122 (MyPlugin:x86_64+0x9f9861)
    #50 juce::AsyncUpdater::AsyncUpdaterMessage::messageCallback() juce_AsyncUpdater.cpp:34 (MyPlugin:x86_64+0x15b73b1)
    #51 juce::MessageQueue::deliverNextMessage() juce_osx_MessageQueue.h:82 (MyPlugin:x86_64+0x15c651b)
    #52 juce::MessageQueue::runLoopCallback() juce_osx_MessageQueue.h:93 (MyPlugin:x86_64+0x15c6449)
    #53 juce::MessageQueue::runLoopSourceCallback(void*) juce_osx_MessageQueue.h:101 (MyPlugin:x86_64+0x15c620b)
    #54 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ <null>:10185136 (CoreFoundation:x86_64h+0x83de1)
    #55 createAndShowEditorOnMessageThread(juce::AudioPluginInstance&) TestUtilities.h:156 (pluginval:x86_64+0x1000b0816)
    #56 ScopedEditorShower::ScopedEditorShower(juce::AudioPluginInstance&) TestUtilities.h:197 (pluginval:x86_64+0x1000b0578)
    #57 ScopedEditorShower::ScopedEditorShower(juce::AudioPluginInstance&) TestUtilities.h:198 (pluginval:x86_64+0x1000b0478)
    #58 EditorTest::runTest(PluginTests&, juce::AudioPluginInstance&) BasicTests.cpp:56 (pluginval:x86_64+0x1000b0172)
    #59 PluginTests::testType(juce::PluginDescription const&)::$_1::operator()() PluginTests.cpp:185 (pluginval:x86_64+0x100072237)
    #60 decltype(std::__1::forward<PluginTests::testType(juce::PluginDescription const&)::$_1&>(fp)()) std::__1::__invoke<PluginTests::testType(juce::PluginDescription const&)::$_1&>(PluginTests::testType(juce::PluginDescription const&)::$_1&) type_traits:4425 (pluginval:x86_64+0x100072120)
    #61 void std::__1::__invoke_void_return_wrapper<void>::__call<PluginTests::testType(juce::PluginDescription const&)::$_1&>(PluginTests::testType(juce::PluginDescription const&)::$_1&) __functional_base:348 (pluginval:x86_64+0x100072080)
    #62 std::__1::__function::__alloc_func<PluginTests::testType(juce::PluginDescription const&)::$_1, std::__1::allocator<PluginTests::testType(juce::PluginDescription const&)::$_1>, void ()>::operator()() functional:1533 (pluginval:x86_64+0x100072020)
    #63 std::__1::__function::__func<PluginTests::testType(juce::PluginDescription const&)::$_1, std::__1::allocator<PluginTests::testType(juce::PluginDescription const&)::$_1>, void ()>::operator()() functional:1707 (pluginval:x86_64+0x10006ff0f)
    #64 std::__1::__function::__value_func<void ()>::operator()() const functional:1860 (pluginval:x86_64+0x10009b7e8)
    #65 std::__1::function<void ()>::operator()() const functional:2419 (pluginval:x86_64+0x10009b518)
    #66 juce::MessageManager::callAsync(std::__1::function<void ()>)::AsyncCallInvoker::messageCallback() juce_MessageManager.cpp:192 (pluginval:x86_64+0x10093c7af)
    #67 juce::MessageQueue::deliverNextMessage() juce_osx_MessageQueue.h:82 (pluginval:x86_64+0x10094de3b)
    #68 juce::MessageQueue::runLoopCallback() juce_osx_MessageQueue.h:93 (pluginval:x86_64+0x10094dd69)
    #69 juce::MessageQueue::runLoopSourceCallback(void*) juce_osx_MessageQueue.h:101 (pluginval:x86_64+0x10094db2b)
    #70 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ <null>:10185136 (CoreFoundation:x86_64h+0x83de1)
    #71 juce::JUCEApplicationBase::main() juce_ApplicationBase.cpp:262 (pluginval:x86_64+0x10092b338)
    #72 juce::JUCEApplicationBase::main(int, char const**) juce_ApplicationBase.cpp:240 (pluginval:x86_64+0x10092b0b8)
    #73 main Main.cpp:183 (pluginval:x86_64+0x100020c3c)

  Location is heap block of size 912 at 0x7b600000c400 allocated by main thread:
    #0 operator new(unsigned long) <null>:10185168 (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x7596b)
    #1 juce::OpenGLContext::Attachment::attach() juce_OpenGLContext.cpp:781 (MyPlugin:x86_64+0x18b4fc0)
    #2 juce::OpenGLContext::Attachment::componentVisibilityChanged() juce_OpenGLContext.cpp:722 (MyPlugin:x86_64+0x18b5542)
    #3 juce::OpenGLContext::Attachment::componentPeerChanged() juce_OpenGLContext.cpp:710 (MyPlugin:x86_64+0x18b548d)
    #4 juce::ComponentMovementWatcher::componentParentHierarchyChanged(juce::Component&) juce_ComponentMovementWatcher.cpp:60 (MyPlugin:x86_64+0x4b4c0e)
    #5 juce::Component::internalHierarchyChanged()::$_5::operator()(juce::ComponentListener&) const juce_Component.cpp:1616 (MyPlugin:x86_64+0x6ed1ca)
    #6 void juce::ListenerList<juce::ComponentListener, juce::Array<juce::ComponentListener*, juce::DummyCriticalSection, 0> >::callChecked<juce::Component::internalHierarchyChanged()::$_5, juce::Component::BailOutChecker>(juce::Component::BailOutChecker const&, juce::Component::internalHierarchyChanged()::$_5&&) juce_ListenerList.h:153 (MyPlugin:x86_64+0x45115a)
    #7 juce::Component::internalHierarchyChanged() juce_Component.cpp:1616 (MyPlugin:x86_64+0x447ef2)
    #8 juce::Component::internalHierarchyChanged() juce_Component.cpp:1623 (MyPlugin:x86_64+0x447f65)
    #9 juce::Component::internalHierarchyChanged() juce_Component.cpp:1623 (MyPlugin:x86_64+0x447f65)
    #10 juce::Component::internalHierarchyChanged() juce_Component.cpp:1623 (MyPlugin:x86_64+0x447f65)
    #11 juce::Component::internalHierarchyChanged() juce_Component.cpp:1623 (MyPlugin:x86_64+0x447f65)
    #12 juce::Component::internalHierarchyChanged() juce_Component.cpp:1623 (MyPlugin:x86_64+0x447f65)
    #13 juce::Component::internalHierarchyChanged() juce_Component.cpp:1623 (MyPlugin:x86_64+0x447f65)
    #14 juce::Component::internalHierarchyChanged() juce_Component.cpp:1623 (MyPlugin:x86_64+0x447f65)
    #15 juce::Component::internalHierarchyChanged() juce_Component.cpp:1623 (MyPlugin:x86_64+0x447f65)
    #16 juce::Component::internalHierarchyChanged() juce_Component.cpp:1623 (MyPlugin:x86_64+0x447f65)
    #17 juce::Component::setVisible(bool) juce_Component.cpp:552 (MyPlugin:x86_64+0x4477f6)
    #18 juce::attachComponentToWindowRefVST(juce::Component*, void*, bool) juce_VST_Wrapper.mm:184 (MyPlugin:x86_64+0x2ef8e)
    #19 JuceVSTWrapper::EditorCompWrapper::attachToHost(JuceVSTWrapper::VstOpCodeArguments) juce_VST_Wrapper.cpp:1342 (MyPlugin:x86_64+0x20ae1)
    #20 JuceVSTWrapper::handleOpenEditor(JuceVSTWrapper::VstOpCodeArguments) juce_VST_Wrapper.cpp:1851 (MyPlugin:x86_64+0x154df)
    #21 JuceVSTWrapper::dispatcher(int, JuceVSTWrapper::VstOpCodeArguments) juce_VST_Wrapper.cpp:1219 (MyPlugin:x86_64+0x13677)
    #22 JuceVSTWrapper::dispatcherCB(Vst2::AEffect*, int, int, long long, void*, float) juce_VST_Wrapper.cpp:1265 (MyPlugin:x86_64+0x9a16)
    #23 juce::VSTPluginInstance::dispatch(int, int, long long, void*, float) const juce_VSTPluginFormat.cpp:1751 (pluginval:x86_64+0x1000fa0cb)
    #24 juce::VSTPluginWindow::dispatch(int, int, int, void*, float) juce_VSTPluginFormat.cpp:3279 (pluginval:x86_64+0x1001aa372)
    #25 juce::VSTPluginWindow::openPluginWindow(void*) juce_VSTPluginFormat.cpp:3075 (pluginval:x86_64+0x1001ad1ab)
    #26 juce::VSTPluginWindow::visibilityChanged() juce_VSTPluginFormat.cpp:2840 (pluginval:x86_64+0x1001aa590)
    #27 juce::Component::sendVisibilityChangeMessage() juce_Component.cpp:564 (pluginval:x86_64+0x100350f91)
    #28 juce::Component::setVisible(bool) juce_Component.cpp:545 (pluginval:x86_64+0x1003509ca)
    #29 juce::VSTPluginWindow::VSTPluginWindow(juce::VSTPluginInstance&) juce_VSTPluginFormat.cpp:2802 (pluginval:x86_64+0x1001a9f7e)
    #30 juce::VSTPluginWindow::VSTPluginWindow(juce::VSTPluginInstance&) juce_VSTPluginFormat.cpp:2772 (pluginval:x86_64+0x1000f92d8)
    #31 juce::VSTPluginInstance::createEditor() juce_VSTPluginFormat.cpp:3486 (pluginval:x86_64+0x1000f9201)
    #32 createAndShowEditorOnMessageThread(juce::AudioPluginInstance&) TestUtilities.h:148 (pluginval:x86_64+0x1000b073d)
    #33 ScopedEditorShower::ScopedEditorShower(juce::AudioPluginInstance&) TestUtilities.h:197 (pluginval:x86_64+0x1000b0578)
    #34 ScopedEditorShower::ScopedEditorShower(juce::AudioPluginInstance&) TestUtilities.h:198 (pluginval:x86_64+0x1000b0478)
    #35 EditorTest::runTest(PluginTests&, juce::AudioPluginInstance&) BasicTests.cpp:56 (pluginval:x86_64+0x1000b0172)
    #36 PluginTests::testType(juce::PluginDescription const&)::$_1::operator()() PluginTests.cpp:185 (pluginval:x86_64+0x100072237)
    #37 decltype(std::__1::forward<PluginTests::testType(juce::PluginDescription const&)::$_1&>(fp)()) std::__1::__invoke<PluginTests::testType(juce::PluginDescription const&)::$_1&>(PluginTests::testType(juce::PluginDescription const&)::$_1&) type_traits:4425 (pluginval:x86_64+0x100072120)
    #38 void std::__1::__invoke_void_return_wrapper<void>::__call<PluginTests::testType(juce::PluginDescription const&)::$_1&>(PluginTests::testType(juce::PluginDescription const&)::$_1&) __functional_base:348 (pluginval:x86_64+0x100072080)
    #39 std::__1::__function::__alloc_func<PluginTests::testType(juce::PluginDescription const&)::$_1, std::__1::allocator<PluginTests::testType(juce::PluginDescription const&)::$_1>, void ()>::operator()() functional:1533 (pluginval:x86_64+0x100072020)
    #40 std::__1::__function::__func<PluginTests::testType(juce::PluginDescription const&)::$_1, std::__1::allocator<PluginTests::testType(juce::PluginDescription const&)::$_1>, void ()>::operator()() functional:1707 (pluginval:x86_64+0x10006ff0f)
    #41 std::__1::__function::__value_func<void ()>::operator()() const functional:1860 (pluginval:x86_64+0x10009b7e8)
    #42 std::__1::function<void ()>::operator()() const functional:2419 (pluginval:x86_64+0x10009b518)
    #43 juce::MessageManager::callAsync(std::__1::function<void ()>)::AsyncCallInvoker::messageCallback() juce_MessageManager.cpp:192 (pluginval:x86_64+0x10093c7af)
    #44 juce::MessageQueue::deliverNextMessage() juce_osx_MessageQueue.h:82 (pluginval:x86_64+0x10094de3b)
    #45 juce::MessageQueue::runLoopCallback() juce_osx_MessageQueue.h:93 (pluginval:x86_64+0x10094dd69)
    #46 juce::MessageQueue::runLoopSourceCallback(void*) juce_osx_MessageQueue.h:101 (pluginval:x86_64+0x10094db2b)
    #47 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ <null>:10185168 (CoreFoundation:x86_64h+0x83de1)
    #48 juce::JUCEApplicationBase::main() juce_ApplicationBase.cpp:262 (pluginval:x86_64+0x10092b338)
    #49 juce::JUCEApplicationBase::main(int, char const**) juce_ApplicationBase.cpp:240 (pluginval:x86_64+0x10092b0b8)
    #50 main Main.cpp:183 (pluginval:x86_64+0x100020c3c)

friendly bump

just observe the same

1 Like

I tried building the OpenGLDemo with thread sanitizer on Catalina. I found one race when dragging the window between displays, but resizing seems to work fine and I haven’t seen any race on scale.

Can you provide steps to reproduce the race on scale, please?

Edit: Just tried running on M1/Monterey and I managed to reproduce the issue.

1 Like

I’ve fixed all the thread sanitizer warnings I was able to trigger. Hopefully this includes the problems you were seeing - if not, please let us know and I’ll take another look.

1 Like

Great. Thanks! :slight_smile: