Fix crash accessing a deleted display using parentDisplay() (fix #3491, fix #2907)

This might be a fix for two frequently reported crashes from Sentry:

1) In Manager::_closeWindow() (#3491): We can reproduce this bug (without
this patch) pressing Ctrl+S to save the active sprite and clicking
randomly in the menu bar (File, Edit, etc. options) to open other menu
boxes (a crash can happen when multiple windows UI is enabled).

2) In set_native_cursor_on_all_displays() (#2907): We weren't able to
reproduce this bug.
This commit is contained in:
David Capello 2022-08-29 19:44:07 -03:00
parent 4817f0a64b
commit bc16ab3a71
2 changed files with 18 additions and 2 deletions

View File

@ -1,5 +1,5 @@
// Aseprite UI Library
// Copyright (C) 2019-2021 Igara Studio S.A.
// Copyright (C) 2019-2022 Igara Studio S.A.
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -75,6 +75,10 @@ namespace ui {
gfx::Size workareaSizeUIScale();
void _setParentDisplay(Display* parentDisplay) {
m_parentDisplay = parentDisplay;
}
private:
Display* m_parentDisplay;
os::WindowRef m_nativeWindow;

View File

@ -1498,7 +1498,7 @@ void Manager::_closeWindow(Window* window, bool redraw_background)
if (// The display can be nullptr if the window was not opened or
// was closed before.
window->ownDisplay()) {
parentDisplay = windowDisplay->parentDisplay();
parentDisplay = (windowDisplay ? windowDisplay->parentDisplay(): nullptr);
ASSERT(parentDisplay);
ASSERT(windowDisplay);
ASSERT(windowDisplay != this->display());
@ -1538,6 +1538,18 @@ void Manager::_closeWindow(Window* window, bool redraw_background)
// delete.
_internal_set_mouse_display(parentDisplay);
// Remove the display that we're going to delete (windowDisplay)
// as parent of any other existent display.
for (auto otherChild : children()) {
if (auto otherWindow = static_cast<Window*>(otherChild)) {
if (otherWindow != window &&
otherWindow->display() &&
otherWindow->display()->parentDisplay() == windowDisplay) {
otherWindow->display()->_setParentDisplay(parentDisplay);
}
}
}
// The ui::Display should destroy the os::Window
delete windowDisplay;