tooltipWindow causing crashes

When rapidly selecting and deleting clips in our timeline (DAW-like app), users sometimes get a crash and it seems like the tooltip component is possibly dereferencing the deleted GUI component.

The crash is happening in the tooltipWindow timerCallback(), where it calls displayTipInternal() and the BAD_ACCESS occurs in Component::getTransform() which I think is being called on the “lastComponentUnderMouse”.
It’s hard to understand how as you’re checking for nullptr at every opportunity and there’s only 2 possible things happening on that line - dereferencing the affineTransform or constructing a new one.

Could it be that the (mac) AutoreleasePool is drained in another thread and the tooltip’s “lastComponentUnderMouse” disappears between checking for nullptr and dereferencing it?

Using JUCE 6.1.4 on Mac OS Catalina to reproduce.

Oh and for the record… this is new since moving from JUCE 5 → 6.1.4

I confirm I get a lot of crash report from various users (mac) that shows the same.

Here is a stack trace :

0   Chataigne                           0x000000010f7f4e1a _Z17handleCrashStatici + 2090
1   Chataigne                           0x000000010f4180dc _ZN4juceL11handleCrashEi + 12
2   libsystem_platform.dylib            0x00007fff6ca145fd _sigtramp + 29
3   libsystem_malloc.dylib              0x00007fff6c9d72d6 tiny_free_no_lock + 1111
4   Chataigne                           0x000000010f586dc9 _ZN4juce13TooltipWindow18displayTipInternalENS_5PointIiEERKNS_6StringENS0_13ShownManuallyE + 313
5   Chataigne                           0x000000010f586951 _ZN4juce13TooltipWindow13timerCallbackEv + 1217
6   Chataigne                           0x000000010f44fe48 _ZN4juce5Timer11TimerThread17CallTimersMessage15messageCallbackEv + 344
7   Chataigne                           0x000000010f44b677 _ZN4juce12MessageQueue21runLoopSourceCallbackEPv + 55
8   CoreFoundation                      0x00007fff32734832 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
9   CoreFoundation                      0x00007fff327347d1 __CFRunLoopDoSource0 + 103
10  CoreFoundation                      0x00007fff327345eb __CFRunLoopDoSources0 + 209
11  CoreFoundation                      0x00007fff3273331a __CFRunLoopRun + 927
12  CoreFoundation                      0x00007fff3273291e CFRunLoopRunSpecific + 462
13  HIToolbox                           0x00007fff3135eabd RunCurrentEventLoopInMode + 292
14  HIToolbox                           0x00007fff3135e7d5 ReceiveNextEventCommon + 584
15  HIToolbox                           0x00007fff3135e579 _BlockUntilNextEventMatchingListInModeWithFilter + 64
16  AppKit                              0x00007fff2f9a5039 _DPSNextEvent + 883
17  AppKit                              0x00007fff2f9a3880 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1352
18  AppKit                              0x00007fff2f99558e -[NSApplication run] + 658
19  Chataigne                           0x000000010f3013fe main + 190
20  libdyld.dylib                       0x00007fff6c81bcc9 start + 1

And here’s a typical stack trace:

|0|0x0000000100eb7342 in juce::Component::getTransform() const  at juce_Component.cpp:1347|
|1|0x0000000100eb7e78 in juce::Component::getApproximateScaleFactorForComponent(juce::Component*) |
|2|0x0000000100f95122 in juce::TooltipWindow::getDesktopScaleFactor() const|
|3|0x0000000100eb450b in juce::Point<int> juce::ScalingHelpers::unscaledScreenPosToScaled<juce::Point<int> >(juce::Component const&, juce::Point<int>)|
|4|0x0000000100f94bfe in juce::TooltipWindow::displayTipInternal(juce::Point<int>, juce::String const&, juce::TooltipWindow::ShownManually) |
|5|0x0000000100f95620 in juce::TooltipWindow::timerCallback()::$_105::operator()() const|
|6|0x0000000100f95499 in juce::TooltipWindow::timerCallback()|
|7|0x0000000100d93785 in juce::Timer::TimerThread::callTimers()|
|8|0x0000000100d93666 in juce::Timer::TimerThread::CallTimersMessage::messageCallback()|
|9|0x0000000100d9a51b in juce::MessageQueue::deliverNextMessage()|
|10|0x0000000100d9a466 in juce::MessageQueue::runLoopCallback()|
|11|0x0000000100d9a185 in juce::MessageQueue::runLoopSourceCallback(void*)|
|13|0x00007fff3250bac0 in __CFRunLoopDoSource0 ()|
|14|0x00007fff3250b8d4 in __CFRunLoopDoSources0 ()|
|15|0x00007fff3250a740 in __CFRunLoopRun ()|
|16|0x00007fff32509bd3 in CFRunLoopRunSpecific ()|
|17|0x00007fff3105f65d in RunCurrentEventLoopInMode ()|
|18|0x00007fff3105f39d in ReceiveNextEventCommon ()|
|19|0x00007fff3105f127 in _BlockUntilNextEventMatchingListInModeWithFilter ()|
|20|0x00007fff2f6cfba4 in _DPSNextEvent ()|
|21|0x00007fff2f6ce380 in -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] ()|
|22|0x00007fff2f6c009e in -[NSApplication run] ()|
|23|0x0000000100d83b62 in juce::MessageManager::runDispatchLoop()|
|24|0x0000000100d83a37 in juce::JUCEApplicationBase::main()|
|25|0x0000000100d8384c in juce::JUCEApplicationBase::main(int, char const**) |
|26|0x0000000100002a53 in main|

Thanks, that’s helpful. I put together a fix for this earlier today, and I expect it to be on develop later this week.

Apologies for the impatience, but was this a tooltip-specific fix, or more generally to do with autorelease, components etc?

I ask because I now have another (separate), bizarre race-condition type crash - also relating to GUI elements being removed.

The fix I found was specifically in the TooltipWindow implementation.

+1 encountered the same crash after update to latest juce 6.1.5

Thanks for your patience. This change should fix the issue: