TreeView: deleteRootItem() followed by a crash

If I click on a component within my tree view that causes my treeview to be rebuilt I can get a crash. It’s quite a complicated setup with two tree views.

But the surprising thing is that even through I’m inside an async callback the test in isMouseDraggingInChildComp for isDragging() returns true. So when we return from deleteRootItem() we still actually have a component in the tree, possibly referring to a now deleted TreeViewItem.

As treeItem here is no longer valid in ContentComponent::updateComponents()

auto& treeItem = comp->getRepresentedItem();
comp->setBounds ({ 0, treeItem.y, getWidth(), treeItem.itemHeight });

JUCE code with the ‘isDragging()’

static bool isMouseDraggingInChildComp (const Component& comp)
{
    for (auto& ms : Desktop::getInstance().getMouseSources())
        if (ms.isDragging())
            if (auto* underMouse = ms.getComponentUnderMouse())
                return (&comp == underMouse || comp.isParentOf (underMouse));

    return false;
}

Perhaps this comment isn’t true?

Something you may want to do with your component is to give it a pointer to
the TreeView that created it. This is perfectly safe, and there's no danger
of it becoming a dangling pointer because the TreeView will always delete
the component before it is itself deleted.

Possibily related to this

Mind boggling stack trace for the crash here:

#0 0x101dc039c in juce::TreeView::ContentComponent::updateComponents() juce_TreeView.cpp:400
#1 0x101dbf164 in juce::TreeView::TreeViewport::updateComponents(bool) juce_TreeView.cpp:816
#2 0x102180a60 in juce::TreeView::TreeViewport::visibleAreaChanged(juce::Rectangle<int> const&) juce_TreeView.cpp:740
#3 0x101915440 in juce::Viewport::updateVisibleArea() juce_Viewport.cpp:461
#4 0x101916c70 in juce::Viewport::componentMovedOrResized(juce::Component&, bool, bool) juce_Viewport.cpp:330
#5 0x101f0442c in juce::Component::sendMovedResizedMessages(bool, bool)::$_14::operator()(juce::ComponentListener&) const juce_Component.cpp:945
#6 0x101f03ee0 in void juce::ListenerList<juce::ComponentListener, juce::Array<juce::ComponentListener*, juce::DummyCriticalSection, 0>>::callCheckedExcluding<juce::Component::sendMovedResizedMessages(bool, bool)::$_14, juce::Component::BailOutChecker>(juce::ComponentListener*, juce::Component::BailOutChecker const&, juce::Component::sendMovedResizedMessages(bool, bool)::$_14&&) juce_ListenerList.h:273
#7 0x101869348 in void juce::ListenerList<juce::ComponentListener, juce::Array<juce::ComponentListener*, juce::DummyCriticalSection, 0>>::callChecked<juce::Component::sendMovedResizedMessages(bool, bool)::$_14, juce::Component::BailOutChecker>(juce::Component::BailOutChecker const&, juce::Component::sendMovedResizedMessages(bool, bool)::$_14&&) juce_ListenerList.h:217
#8 0x101869118 in juce::Component::sendMovedResizedMessages(bool, bool) juce_Component.cpp:943
#9 0x101868a8c in juce::Component::sendMovedResizedMessagesIfPending() juce_Component.cpp:904
#10 0x101868694 in juce::Component::setBounds(int, int, int, int) juce_Component.cpp:890
#11 0x10184e29c in juce::Component::setSize(int, int) juce_Component.cpp:954
#12 0x101dbef2c in juce::TreeView::TreeViewport::handleAsyncUpdate() juce_TreeView.cpp:794
#13 0x101a2f03c in juce::TreeView::TreeViewport::recalculatePositions(juce::TreeView::TreeViewport::Async, std::__1::optional<juce::Point<int>>) juce_TreeView.cpp:770
#14 0x101a2ece4 in juce::TreeView::setRootItem(juce::TreeViewItem*) juce_TreeView.cpp:1007
#15 0x10135f6e8 in presetbrowser::ReusablePresetBrowser::PresetView::setFolder(juce::String const&, bool, bool) ReusablePresetBrowser.cpp:338
#16 0x10134db14 in presetbrowser::ReusablePresetBrowser::FolderView::TreeItem::itemSelectionChanged(bool) ReusablePresetBrowser.cpp:1147
#17 0x101a32030 in juce::TreeViewItem::setSelected(bool, bool, juce::NotificationType) juce_TreeView.cpp:1773
#18 0x101378f04 in presetbrowser::ReusablePresetBrowser::FolderView::selectFirstFolder() ReusablePresetBrowser.cpp:683
#19 0x101378bc0 in presetbrowser::ReusablePresetBrowser::FolderView::updateView(bool) ReusablePresetBrowser.cpp:638
#20 0x10132e480 in presetbrowser::ReusablePresetBrowser::FolderView::setShowTab(juce::String const&) ReusablePresetBrowser.cpp:618
#21 0x10132e800 in presetbrowser::ReusablePresetBrowser::FolderView::revealExistingFolder() ReusablePresetBrowser.cpp:701
#22 0x101378bcc in presetbrowser::ReusablePresetBrowser::FolderView::updateView(bool) ReusablePresetBrowser.cpp:640
#23 0x10132ea68 in presetbrowser::ReusablePresetBrowser::FolderView::rebuild() ReusablePresetBrowser.cpp:650
#24 0x10132ea2c in presetbrowser::ReusablePresetBrowser::rebuildRequired() ReusablePresetBrowser.cpp:1274
#25 0x1012a107c in void juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::callCheckedExcluding<juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::DummyBailOutChecker>(presetbrowser::BrowserDataModel::Listener*, juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::DummyBailOutChecker const&, void (presetbrowser::BrowserDataModel::Listener::*)())::'lambda'(presetbrowser::BrowserDataModel::Listener&)::operator()(presetbrowser::BrowserDataModel::Listener&) const juce_ListenerList.h:332
#26 0x1012a0bc8 in void juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::callCheckedExcluding<void juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::callCheckedExcluding<juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::DummyBailOutChecker>(presetbrowser::BrowserDataModel::Listener*, juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::DummyBailOutChecker const&, void (presetbrowser::BrowserDataModel::Listener::*)())::'lambda'(presetbrowser::BrowserDataModel::Listener&), juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::DummyBailOutChecker>(presetbrowser::BrowserDataModel::Listener*, juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::DummyBailOutChecker const&, juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::DummyBailOutChecker&&) juce_ListenerList.h:273
#27 0x1012a0418 in void juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::callCheckedExcluding<juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::DummyBailOutChecker>(presetbrowser::BrowserDataModel::Listener*, juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::DummyBailOutChecker const&, void (presetbrowser::BrowserDataModel::Listener::*)()) juce_ListenerList.h:330
#28 0x1012a00e8 in void juce::ListenerList<presetbrowser::BrowserDataModel::Listener, juce::Array<presetbrowser::BrowserDataModel::Listener*, juce::DummyCriticalSection, 0>>::call<>(void (presetbrowser::BrowserDataModel::Listener::*)()) juce_ListenerList.h:282
#29 0x10129fe1c in presetbrowser::BrowserDataModel::rebuildBrowser()::'lambda'()::operator()() const PresetBrowserModel.h:130
#30 0x10129fc64 in decltype(std::declval<presetbrowser::BrowserDataModel::rebuildBrowser()::'lambda'()&>()()) std::__1::__invoke[abi:ue170006]<presetbrowser::BrowserDataModel::rebuildBrowser()::'lambda'()&>(presetbrowser::BrowserDataModel::rebuildBrowser()::'lambda'()&) invoke.h:340
#31 0x10129fc1c in void std::__1::__invoke_void_return_wrapper<void, true>::__call[abi:ue170006]<presetbrowser::BrowserDataModel::rebuildBrowser()::'lambda'()&>(presetbrowser::BrowserDataModel::rebuildBrowser()::'lambda'()&) invoke.h:415
#32 0x10129fbf8 in std::__1::__function::__alloc_func<presetbrowser::BrowserDataModel::rebuildBrowser()::'lambda'(), std::__1::allocator<presetbrowser::BrowserDataModel::rebuildBrowser()::'lambda'()>, void ()>::operator()[abi:ue170006]() function.h:193
#33 0x10129baf4 in std::__1::__function::__func<presetbrowser::BrowserDataModel::rebuildBrowser()::'lambda'(), std::__1::allocator<presetbrowser::BrowserDataModel::rebuildBrowser()::'lambda'()>, void ()>::operator()() function.h:364
#34 0x100d90170 in std::__1::__function::__value_func<void ()>::operator()[abi:ue170006]() const function.h:518
#35 0x100d90038 in std::__1::function<void ()>::operator()() const function.h:1169
#36 0x10126b9a0 in jcf::MultiAsyncUpdater::handleAsyncUpdate() multi_async_updater.h:35
#37 0x102b641c0 in juce::AsyncUpdater::AsyncUpdaterMessage::messageCallback() juce_AsyncUpdater.cpp:46

Bump :slight_smile: