diff options
author | mread <qt-info@nokia.com> | 2010-04-06 13:05:01 (GMT) |
---|---|---|
committer | mread <qt-info@nokia.com> | 2010-04-07 08:29:10 (GMT) |
commit | 71df6edab122730c38ac238e168a4cc35b6f4857 (patch) | |
tree | 4fa146bf9ce4f6edcb5db256cae10dc7f01aed25 | |
parent | 440b48c8601e8a4bb31858c8c5521a0ab8961ef8 (diff) | |
download | Qt-71df6edab122730c38ac238e168a4cc35b6f4857.zip Qt-71df6edab122730c38ac238e168a4cc35b6f4857.tar.gz Qt-71df6edab122730c38ac238e168a4cc35b6f4857.tar.bz2 |
QTBUG-4887 and other exception safety fixes
This change includes a fix for QTBUG-4887 and other exception safety
problems found while testing it.
The QTBUG-4887 fix is to qimage.cpp. QImage doesn't throw exceptions on
failure like a proper class should, instead it tries to fail "nice".
What happens here is that setAlphaChannel would crash on OOM as after
the convertToFormat call, d could be NULL. This new version checks the
result of the conversion before using it.
The other fixes are all cases where exceptions were thrown from
destructors. I added code to the test app to help debug these cases,
and I fixed all the problems I found.
With these changes, tst_exceptionsafety_objects runs and passes on the
Symbian emulator.
Reviewed-by: Shane Kearns
-rw-r--r-- | src/gui/image/qimage.cpp | 6 | ||||
-rw-r--r-- | src/gui/kernel/qapplication_s60.cpp | 9 | ||||
-rw-r--r-- | src/gui/kernel/qwidget.cpp | 8 | ||||
-rw-r--r-- | src/gui/widgets/qmenu.cpp | 14 | ||||
-rw-r--r-- | tests/auto/exceptionsafety_objects/tst_exceptionsafety_objects.cpp | 19 |
5 files changed, 45 insertions, 11 deletions
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 4f5efa1..5d2b4c0 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -5667,7 +5667,11 @@ void QImage::setAlphaChannel(const QImage &alphaChannel) detach(); - *this = convertToFormat(QImage::Format_ARGB32_Premultiplied); + QImage converted = convertToFormat(QImage::Format_ARGB32_Premultiplied); + if (!converted.isNull()) + *this = converted; + else + return; // Slight optimization since alphachannels are returned as 8-bit grays. if (alphaChannel.d->depth == 8 && alphaChannel.isGrayscale()) { diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 37d1b62..e986ce9 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -372,8 +372,13 @@ QSymbianControl::~QSymbianControl() { if (S60->curWin == this) S60->curWin = 0; - if (!QApplicationPrivate::is_app_closing) - setFocusSafely(false); + if (!QApplicationPrivate::is_app_closing) { + QT_TRY { + setFocusSafely(false); + } QT_CATCH(const std::exception&) { + // ignore exceptions, nothing can be done + } + } S60->appUi()->RemoveFromStack(this); delete m_longTapDetector; } diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index cd943cd..e180001 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -1487,8 +1487,12 @@ QWidget::~QWidget() if (QWidgetPrivate::allWidgets) // might have been deleted by ~QApplication QWidgetPrivate::allWidgets->remove(this); - QEvent e(QEvent::Destroy); - QCoreApplication::sendEvent(this, &e); + QT_TRY { + QEvent e(QEvent::Destroy); + QCoreApplication::sendEvent(this, &e); + } QT_CATCH(const std::exception&) { + // if this fails we can't do anything about it but at least we are not allowed to throw. + } } int QWidgetPrivate::instanceCounter = 0; // Current number of widget instances diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index a9978f9..c7573bf 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -1406,12 +1406,14 @@ QMenu::QMenu(QMenuPrivate &dd, QWidget *parent) QMenu::~QMenu() { Q_D(QMenu); - QHash<QAction *, QWidget *>::iterator it = d->widgetItems.begin(); - for (; it != d->widgetItems.end(); ++it) { - if (QWidget *widget = it.value()) { - QWidgetAction *action = static_cast<QWidgetAction *>(it.key()); - action->releaseWidget(widget); - *it = 0; + if (!d->widgetItems.isEmpty()) { // avoid detach on shared null hash + QHash<QAction *, QWidget *>::iterator it = d->widgetItems.begin(); + for (; it != d->widgetItems.end(); ++it) { + if (QWidget *widget = it.value()) { + QWidgetAction *action = static_cast<QWidgetAction *>(it.key()); + action->releaseWidget(widget); + *it = 0; + } } } diff --git a/tests/auto/exceptionsafety_objects/tst_exceptionsafety_objects.cpp b/tests/auto/exceptionsafety_objects/tst_exceptionsafety_objects.cpp index 4433c7a..91d1a44 100644 --- a/tests/auto/exceptionsafety_objects/tst_exceptionsafety_objects.cpp +++ b/tests/auto/exceptionsafety_objects/tst_exceptionsafety_objects.cpp @@ -43,6 +43,7 @@ #include <QtTest/QtTest> #include <stddef.h> +#include <exception> QT_USE_NAMESPACE @@ -285,8 +286,26 @@ void tst_ExceptionSafetyObjects::safeMessageHandler(QtMsgType type, const char * allocFailer.reactivateAt(currentIndex); } +typedef void (*PVF)(); +PVF defaultTerminate; +void debugTerminate() +{ + // you can detect uncaught exceptions with a breakpoint in here + (*defaultTerminate)(); +} + +PVF defaultUnexpected; +void debugUnexpected() +{ + // you can detect unexpected exceptions with a breakpoint in here + (*defaultUnexpected)(); +} + void tst_ExceptionSafetyObjects::initTestCase() { + // set handlers for bad exception cases, you might want to step in and breakpoint the default handlers too + defaultTerminate = std::set_terminate(&debugTerminate); + defaultUnexpected = std::set_unexpected(&debugUnexpected); testMessageHandler = qInstallMsgHandler(safeMessageHandler); QVERIFY(AllocFailer::initialize()); |