More issues with JUCE_COREGRAPHICS_RENDER_WITH_MULTIPLE_PAINT_CALLS and Metal

With latest changes (this is even before - 61fd8827e17fb22190e260c2091c0460fbecfb05),

I get asan (heap-use-after-free) warnings. I’ll try to provide a simple juce example (I don’t have one yet that reproduces this).

==4658==ERROR: AddressSanitizer: heap-use-after-free on address 0x000135b62dc0 at pc 0x00010c93dbc4 bp 0x00016d6f8190 sp 0x00016d6f7948
READ of size 16 at 0x000135b62dc0 thread T0
    #0 0x10c93dbc0 in __asan_memcpy+0x1a4 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3dbc0)
    #1 0x104d05d34 in bool juce::CoreGraphicsMetalLayerRenderer<NSView>::drawRectangleList<juce::NSViewComponentPeer::setNeedsDisplayRectangles()::'lambda0'()::operator()() const::'lambda'(CGContext*, CGRect)>(NSView*, float, juce::NSViewComponentPeer::setNeedsDisplayRectangles()::'lambda0'()::operator()() const::'lambda'(CGContext*, CGRect)&&, juce::RectangleList<float> const&) juce_mac_CGMetalLayerRenderer.h:136
    #2 0x104d0245c in juce::NSViewComponentPeer::setNeedsDisplayRectangles()::'lambda0'()::operator()() const juce_mac_NSViewComponentPeer.mm:1081
    #3 0x104d010ac in juce::NSViewComponentPeer::setNeedsDisplayRectangles() juce_mac_NSViewComponentPeer.mm:1092
    #4 0x104db46fc in juce::NSViewComponentPeer::onDisplaySourceCallback() juce_mac_NSViewComponentPeer.mm:1789
    #5 0x104db46a0 in invocation function for block in juce::NSViewComponentPeer::createCVDisplayLink() juce_mac_NSViewComponentPeer.mm:1814
    #6 0x10c93f270 in __wrap_dispatch_source_set_event_handler_block_invoke+0xc0 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3f270)
    #7 0x10c5ee3a4 in _dispatch_client_callout+0x10 (libdispatch.dylib:arm64e+0x63a4)
    #8 0x10c5f1ca4 in _dispatch_continuation_pop+0x328 (libdispatch.dylib:arm64e+0x9ca4)
    #9 0x10c60cc74 in _dispatch_source_invoke+0x6c8 (libdispatch.dylib:arm64e+0x24c74)
    #10 0x10c6013a8 in _dispatch_main_queue_drain+0x310 (libdispatch.dylib:arm64e+0x193a8)
    #11 0x10c601084 in _dispatch_main_queue_callback_4CF+0x28 (libdispatch.dylib:arm64e+0x19084)
    #12 0x1988c2a28 in __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__+0xc (CoreFoundation:arm64e+0xc6a28)
    #13 0x19887fcb4 in __CFRunLoopRun+0x9e0 (CoreFoundation:arm64e+0x83cb4)
    #14 0x19887eb30 in CFRunLoopRunSpecific+0x254 (CoreFoundation:arm64e+0x82b30)
    #15 0x1a14be334 in RunCurrentEventLoopInMode+0x120 (HIToolbox:arm64e+0x32334)
    #16 0x1a14be0b0 in ReceiveNextEventCommon+0x230 (HIToolbox:arm64e+0x320b0)
    #17 0x1a14bde64 in _BlockUntilNextEventMatchingListInModeWithFilter+0x44 (HIToolbox:arm64e+0x31e64)
    #18 0x19b3e6518 in _DPSNextEvent+0x358 (AppKit:arm64e+0x41518)
    #19 0x19b3e4e10 in -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]+0x52c (AppKit:arm64e+0x3fe10)
    #20 0x19b3d6fdc in -[NSApplication run]+0x250 (AppKit:arm64e+0x31fdc)
    #21 0x103ce391c in juce::MessageManager::runDispatchLoop() juce_mac_MessageManager.mm:359
    #22 0x103ce3560 in juce::JUCEApplicationBase::main() juce_ApplicationBase.cpp:262
    #23 0x103ce3114 in juce::JUCEApplicationBase::main(int, char const**) juce_ApplicationBase.cpp:240
    #24 0x1027086d0 in main juce_audio_plugin_client_Standalone.cpp:47
    #25 0x10c539088 in start+0x204 (dyld:arm64e+0x5088)

0x000135b62dc0 is located 64 bytes inside of 256-byte region [0x000135b62d80,0x000135b62e80)
freed by thread T0 here:
    #0 0x10c93fddc in wrap_realloc+0x9c (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3fddc)
    #1 0x1044de194 in void juce::HeapBlock<juce::Rectangle<float>, false>::realloc<unsigned long>(unsigned long, unsigned long) juce_HeapBlock.h:293
    #2 0x1044ddfbc in std::__1::enable_if<IsTriviallyCopyable<juce::Rectangle<float> >::value, void>::type juce::ArrayBase<juce::Rectangle<float>, juce::DummyCriticalSection>::setAllocatedSizeInternal<juce::Rectangle<float> >(int) juce_ArrayBase.h:431
    #3 0x1044dde70 in juce::ArrayBase<juce::Rectangle<float>, juce::DummyCriticalSection>::setAllocatedSize(int) juce_ArrayBase.h:217
    #4 0x1044e03ac in juce::ArrayBase<juce::Rectangle<float>, juce::DummyCriticalSection>::shrinkToNoMoreThan(int) juce_ArrayBase.h:236
    #5 0x1044dff90 in juce::Array<juce::Rectangle<float>, juce::DummyCriticalSection, 0>::minimiseStorageAfterRemoval() juce_Array.h:1149
    #6 0x1044dfa90 in juce::Array<juce::Rectangle<float>, juce::DummyCriticalSection, 0>::removeInternal(int) juce_Array.h:1143
    #7 0x1044dec60 in juce::Array<juce::Rectangle<float>, juce::DummyCriticalSection, 0>::remove(int) juce_Array.h:772
    #8 0x104dc2298 in juce::RectangleList<float>::add(juce::Rectangle<float>) juce_RectangleList.h:131
    #9 0x104daced8 in juce::NSViewComponentPeer::repaint(juce::Rectangle<int> const&) juce_mac_NSViewComponentPeer.mm:1023
    #10 0x10459a97c in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1971
    #11 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #12 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #13 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #14 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #15 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #16 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #17 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #18 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #19 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #20 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #21 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #22 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #23 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #24 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #25 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #26 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #27 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #28 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #29 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943

previously allocated by thread T0 here:
    #0 0x10c93fddc in wrap_realloc+0x9c (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3fddc)
    #1 0x1044de194 in void juce::HeapBlock<juce::Rectangle<float>, false>::realloc<unsigned long>(unsigned long, unsigned long) juce_HeapBlock.h:293
    #2 0x1044ddfbc in std::__1::enable_if<IsTriviallyCopyable<juce::Rectangle<float> >::value, void>::type juce::ArrayBase<juce::Rectangle<float>, juce::DummyCriticalSection>::setAllocatedSizeInternal<juce::Rectangle<float> >(int) juce_ArrayBase.h:431
    #3 0x1044dde70 in juce::ArrayBase<juce::Rectangle<float>, juce::DummyCriticalSection>::setAllocatedSize(int) juce_ArrayBase.h:217
    #4 0x1044dd5b0 in juce::ArrayBase<juce::Rectangle<float>, juce::DummyCriticalSection>::ensureAllocatedSize(int) juce_ArrayBase.h:228
    #5 0x104dc6a80 in void juce::ArrayBase<juce::Rectangle<float>, juce::DummyCriticalSection>::addArray<juce::Array<juce::Rectangle<float>, juce::DummyCriticalSection, 0> >(juce::Array<juce::Rectangle<float>, juce::DummyCriticalSection, 0> const&) juce_ArrayBase.h:300
    #6 0x104dc5e1c in void juce::Array<juce::Rectangle<float>, juce::DummyCriticalSection, 0>::addArray<juce::Array<juce::Rectangle<float>, juce::DummyCriticalSection, 0> >(juce::Array<juce::Rectangle<float>, juce::DummyCriticalSection, 0> const&) juce_Array.h:639
    #7 0x104dc285c in juce::RectangleList<float>::add(juce::Rectangle<float>) juce_RectangleList.h:152
    #8 0x104daced8 in juce::NSViewComponentPeer::repaint(juce::Rectangle<int> const&) juce_mac_NSViewComponentPeer.mm:1023
    #9 0x10459a97c in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1971
    #10 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #11 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #12 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #13 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #14 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #15 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #16 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #17 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #18 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #19 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #20 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #21 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #22 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #23 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #24 0x10459b52c in juce::Component::internalRepaint(juce::Rectangle<int>) juce_Component.cpp:1943
    #25 0x10459ac88 in juce::Component::internalRepaintUnchecked(juce::Rectangle<int>, bool) juce_Component.cpp:1977
    #26 0x10456ee84 in juce::Component::repaint() juce_Component.cpp:1919
    #27 0x1028f9798 in PerformView::update(double) PerformView.cpp:158
    #28 0x102acaf54 in TickAudioProcessorEditor::timerCallback() PluginEditor.cpp:405
    #29 0x103d20a38 in juce::Timer::TimerThread::callTimers() juce_Timer.cpp:115

SUMMARY: AddressSanitizer: heap-use-after-free (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3dbc0) in __asan_memcpy+0x1a4
Shadow bytes around the buggy address:
  0x007026b8c560: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x007026b8c570: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x007026b8c580: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x007026b8c590: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x007026b8c5a0: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa
=>0x007026b8c5b0: fd fd fd fd fd fd fd fd[fd]fd fd fd fd fd fd fd
  0x007026b8c5c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x007026b8c5d0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x007026b8c5e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x007026b8c5f0: fd fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x007026b8c600: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==4658==ABORTING
(lldb) thread info -s
thread #1: tid = 0x46c213, 0x000000010c948870 libclang_rt.asan_osx_dynamic.dylib`__asan::AsanDie(), name = 'JUCE Message Thread', queue = 'com.apple.main-thread', stop reason = Use of deallocated memory

{
  "access_size": 16,
  "access_type": 0,
  "address": 5196099008,
  "description": "heap-use-after-free",
  "instrumentation_class": "AddressSanitizer",
  "pc": 4505983940,
  "stop_type": "fatal_error"
}
(lldb) 

More insight (as I’m now able to easily reproduce this on the demos).

In my case it happens when there’s a juce::Component which is alwaysOnTop.
While the top level component under it has a timerCallback that calls a child that calls on each of his childs repaint()…

I hope I’ll be able to make a reproducible example.

In my case I’ve been able to mitigate.

I had an object that from his paint (Graphics&) called a label with:
label.setColour (juce::Label::textColourId, textColor);

I’ve now placed this inside MessageManager::callAsync .

I still hope to provide here a simple case that reproduces the issue.

A simple test case would be appreciated, thanks!