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