On 22 May 2024, at 17:31, Thiago Macieira <thiago.macie...@intel.com> wrote:

On Wednesday 22 May 2024 06:38:28 GMT-3 Volker Hilsheimer via Development
wrote:
As long as Qt is built with exception support

We don't support toggling that on and off any more and haven't for a while.

QtCore and QtGui are compiled with exceptions enabled; all the other modules
are not. In paticular, QtWidgets is not and that therefore applies to
QApplication::notify(). That means you MUST NOT let exceptions run through the
event loop of a Widgets application.

You shouldn't let it happen for any application because Bad Things Will
Happen™ because we don't test what happens if you do. Your very best bet is
that you end up back in main() where you can do an emergency save using non-Qt
code and terminate the application. But since we don't test, we can't
guarantee that even the exceptions-enabled code in QtCore and QtGui won't just
crash because of some unsuspected condition being violated.

There might be code paths (esp on macOS) that go into the native functions
and back into Qt, and perhaps some of those native stack frames eat the
exception or don’t pass it on otherwise.

As far as I understand, the problem is that on ARM, there *is* no native stack
frame, unlike on x86. Stack unwinding on x86 is very frequently possible
because the architecture saves the return address on the stack and most code
is compiled with frame pointers, even when exceptions are disabled. On ARM and
other RISC architectures, the return address is saved in a register and it's
the responsibility of the prologue of the called function to save it somewhere
in the stack if it is not a leaf function. The problem is answering: where?

This requires reading the unwind information.

Which isn't present in QtWidgets.

That makes perfect sense, thanks!

That explains why Dennis reports being able to throw through
QApplication::notify() on Intel Macs but not on ARM Macs.

Plus, yes, we often have frames from third party libraries in our stack that
aren't capable of unwinding the stack either. Therefore, the Qt recommendation
is that you treat all event handlers and all slot invocations as noexcept and
catch your own exceptions before they go back to Qt code. This is the reason
why we decided it was ok to disable exceptions in QtWidgets itself, because we
didn't think we could guarantee survivability in the first place.


From what I see, the problem is bigger than “don’t let exceptions run through 
the event loop” though. In my example, even a try/catch around calling the 
parent class implementation of QWidget::event will not work, because 
QWidget::event doesn’t have the unwind information.

    bool event(QEvent *e) override {
        try {
            return QWidget::event(e);
        }
        catch (const std::runtime_error& e) {
            qDebug() << "Exception in event()!" << e.what();
        }
        return false;
    }


In practice, that means that you cannot meaningfully use exceptions in a Qt 
application (or library with possible binary compatibility commitments) unless 
you catch them on the lowest stack frame that is not Qt. Which is perhaps not 
terribly useful.

So the question is what we want to do about 
https://doc.qt.io/qt-6/exceptionsafety.html. It starts with the disclaimer that 
this is not feature complete, but that’s been the case since the dawn of time, 
and on ARM, even common cases won’t work as advertised here. Perhaps a good 
start would be to add a warning that none of this will work on ARM 
architecture, unless Qt is compiled explicitly with exception handling enabled? 
Which then might ideally be something we support in the build system through a 
toggle.

FWW, I don’t see EXCEPTIONS set in QtGui’s CMakeLists.txt, only in corelib, 
concurrent, and testlib (plus the networklistmanager plugin, syncqt, 
shadertools, and a bunch of 3rd party code).

Volker

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development

Reply via email to