Closed nununoisy closed 9 months ago
Thanks a lot for the bug report.
I couldn't reproduce the issue on Linux. And I don't have a Qt setup on my windows VM at the moment. Do you have a backtrace by any chance? As I workaround, i recommend not using the Qt backend on windows.
(Opening the main.slint from gbpresenter with the slint-viewer, i noticed another panic fixed in https://github.com/slint-ui/slint/pull/4140)
I've tried to reproduce this but I can't seem to make it crash. This is with current slint, Qt 6.5.1 (MSVC). Here's a clip. Am I doing the wrong steps somehow?
https://github.com/slint-ui/slint/assets/1486/6c9d4e74-cc02-4bf2-9da1-7ab94f119c80
I did a bit of debugging and I think I figured out what's going on:
PopupWindow
struct is created, a QtWindow
is created and placed into a PopupWindowLocation::TopLevel
tuple struct. The PopupWindow
is then placed into the parent window's active popup RefCell
.WindowInner::close_popup()
is called.WindowInner::close_popup()
closes the popup by taking the PopupWindow
from the active popup RefCell
and dropping it before returning.PopupWindow
drops its PopupWindowLocation
tuple struct.PopupWindowLocation
tuple struct drops its QtWindow
.QtWindow
struct drops its QtWidgetPtr
.QtWidgetPtr
calls ~std::unique_ptr<QWidget>()
, which destroys the SlintWidget
it points to.SlintWidget
will close the Qt window as it is destroyed.QWidgetWindow::handleMouseEvent(QEvent*)
is called.QWidgetWindow::handleMouseEvent(QEvent*)
gets a pointer to the current active popup using QApplication::activePopupWidget()
.QContextMenuEvent
and forward it to the active popup widget.While forwarding the QContextMenuEvent
, I noticed that the active popup widget pointer was nullptr
, which explains why the program segfaulted. I think the problem here is that the SlintWidget
is sometimes deleted before all mouse events are delivered. The docs for QObject::~QObject()
state that a crash may occur if an object is deleted while there are undelivered pending events waiting for it. Although the mouse event handler attempts to check to see if the popup closes to prevent a crash like this, the check doesn't work as Slint always eats window close events so it can forward them to downstream code without blocking. The fact that this is potentially a race condition might also explain why it isn't consistent.
A potential solution would be to have QtWindow
hold a raw SlintWidget
pointer instead of a smart pointer, and add a custom Drop
impl that:
SlintWidget
so that it can continue to exist while there are still pending events.QWindow::close()
or QWindow::hide()
to ensure the window disappears.QObject::disconnect()
with no arguments to disconnect all signals so that no more pending events may be forwarded to the SlintWidget
.QObject::deleteLater()
to signal to Qt that it should delete the SlintWidget
when there are no more pending events.Thanks for the detailed debug! This is very useful. This is strange that we can't reproduce it for us. But you might be right that we should use deleteLater to destroy. We can probably do something like that: https://stackoverflow.com/a/41408511
Steps to reproduce:
PopupWindow
with the propertyclose-on-click
set totrue
.Expected outcome: The
PopupWindow
should close, matching the behavior of left- or middle-clicking on the application window.Actual outcome: The application crashes with a return of
0xc0000005 (STATUS_ACCESS_VIOLATION)
.You can try reproducing the bug in GBPresenter v0.6.0 - an affected
PopupWindow
can be opened by clicking on the info button in the top right corner. I can also reproduce the bug withinslint-viewer
when viewingmain.slint
, so I'm confident that the bug is in Slint.I am using: