Details
-
Bug
-
Resolution: Done
-
P2: Important
-
4.5.2
-
None
-
95e438189a36c71d632099b3873557103697bc3b
Description
We noticed a problem in Qt, when you throw an exception from a menu item's slot. Below I have attached the code to reproduce the problem in Qt's "mainwindows/menus" example.
When you run this code in debug configuration, and choose Help -> About, the application throws an exception (not visible other than in console). Ok, so far no problem. But, then try to choose Help -> About again. When you hover your mouse over About, the assertion happens. This is because the exception interrupted the method activateCausedStack() in qmenu.cpp. This method is not exception-safe, because the activationRecursionGuard boolean is cleared only when this method successfully completes. Any exception will cause the method to not finish, and the problem occurs. Most likely Qt code has similar problems elsewhere.
A nice fix for this is to create a class which takes care of clearing any boolean flags, when it's destructor is ran. Make an object of this class at the beginning of the method, the constructor setting the boolean to true. Then it will be cleared even if the method is interrupted, because the object is destroyed when the method ends. No matter if it was successful or not.
Modify Qt's "mainwindows/menus" example as follows:
main.cpp:
#include <QApplication>
#include <exception>
#include <iostream>
#include "mainwindow.h"
class MyQApplication : public QApplication
{
public:
MyQApplication(int &argc, char *argv[]) : QApplication(argc, argv)
{
}
bool notify(QObject *receiver, QEvent *event)
{
try
{
return QApplication::notify(receiver, event);
}
catch(std::exception &e)
{
std::cout << e.what() << std::endl;
}
}
};
int main(int argc, char *argv[])
{
MyQApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
MainWindow.cpp:
// add this include
#include <exception>
// throw exception in about()
void MainWindow::about()
{
throw std::range_error("error test");
infoLabel->setText(tr("Invoked <b>Help|About</b>"));
QMessageBox::about(this, tr("About Menu"),
tr("The <b>Menu</b> example shows how to create "
"menu-bar menus and context menus."));
}