From 85ccffc829fd0d5a29e84f90bcab460770ea8601 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 6 May 2010 21:09:50 +0200 Subject: Fix crash with stylesheet if widget change style in the changeEvent The problem appeared with KLineEdit and its proxy style. When setting a stylesheet, we create a QStyleSheetStyle in 9# and set it to the widget, which receive a changeEvent, that will set again the style so 3# will create a new QStyleSheetStyle with the new proxy. and set it. in 2# we will dereference the 'old' QStyleSheetStyle (the one created in #9) that will destroy it. Then, later in #7, we will still access that style ('newStyle') and we crash 0# QStyleSheetStyle::~QStyleSheetStyle() 1# QStyleSheetStyle::deref() 2# QWidgetPrivate::setStyle_helper(QStyle*, bool, bool) 3# QWidget::setStyle(QStyle*) (qwidget.cpp:2523) 4# ChangeEventWidget::changeEvent(QEvent*) [...] 6# QCoreApplication::sendEvent(QObject*, QEvent*) 7# QWidgetPrivate::setStyle_helper(QStyle*, bool, bool) 9# QWidget::setStyleSheet(QString const&) (qwidget.cpp:2470) The solution is to change the order, and do not use 'newstyle' after we sent the event. The origStyle is now protected wy a QWeakPointer, but this is just for safety reason and not related to the crash. Reviewed-by: JBache --- src/gui/kernel/qwidget.cpp | 20 +++++++------- .../auto/qstylesheetstyle/tst_qstylesheetstyle.cpp | 31 +++++++++++++++++++++- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 20d1d30..be0a8a0 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -2535,7 +2535,7 @@ void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate, bool Q_Q(QWidget); QStyle *oldStyle = q->style(); #ifndef QT_NO_STYLE_STYLESHEET - QStyle *origStyle = 0; + QWeakPointer origStyle; #endif #ifdef Q_WS_MAC @@ -2549,7 +2549,7 @@ void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate, bool createExtra(); #ifndef QT_NO_STYLE_STYLESHEET - origStyle = extra->style; + origStyle = extra->style.data(); #endif extra->style = newStyle; } @@ -2578,23 +2578,23 @@ void QWidgetPrivate::setStyle_helper(QStyle *newStyle, bool propagate, bool } } - QEvent e(QEvent::StyleChange); - QApplication::sendEvent(q, &e); -#ifdef QT3_SUPPORT - q->styleChange(*oldStyle); -#endif - #ifndef QT_NO_STYLE_STYLESHEET if (!qobject_cast(newStyle)) { - if (const QStyleSheetStyle* cssStyle = qobject_cast(origStyle)) { + if (const QStyleSheetStyle* cssStyle = qobject_cast(origStyle.data())) { cssStyle->clearWidgetFont(q); } } #endif + QEvent e(QEvent::StyleChange); + QApplication::sendEvent(q, &e); +#ifdef QT3_SUPPORT + q->styleChange(*oldStyle); +#endif + #ifndef QT_NO_STYLE_STYLESHEET // dereference the old stylesheet style - if (QStyleSheetStyle *proxy = qobject_cast(origStyle)) + if (QStyleSheetStyle *proxy = qobject_cast(origStyle.data())) proxy->deref(); #endif } diff --git a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp index e0512a9..e370309 100644 --- a/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp +++ b/tests/auto/qstylesheetstyle/tst_qstylesheetstyle.cpp @@ -98,6 +98,7 @@ private slots: void complexWidgetFocus(); void task188195_baseBackground(); void task232085_spinBoxLineEditBg(); + void changeStyleInChangeEvent(); //at the end because it mess with the style. void widgetStyle(); @@ -1256,7 +1257,7 @@ void tst_QStyleSheetStyle::proxyStyle() QStyleOptionViewItemV4 opt; opt.initFrom(w); opt.features |= QStyleOptionViewItemV2::HasCheckIndicator; - QVERIFY(pb5->style()->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, + QVERIFY(pb5->style()->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &opt, pb5).width() == 3); delete w; delete proxy; @@ -1579,6 +1580,34 @@ void tst_QStyleSheetStyle::task232085_spinBoxLineEditBg() .toLocal8Bit().constData()); } +class ChangeEventWidget : public QWidget +{ public: + void changeEvent(QEvent * event) + { + if(event->type() == QEvent::StyleChange) { + static bool recurse = false; + if (!recurse) { + recurse = true; + QStyle *style = new QMotifStyle; + style->setParent(this); + setStyle(style); + recurse = false; + } + } + QWidget::changeEvent(event); + } +}; + +void tst_QStyleSheetStyle::changeStyleInChangeEvent() +{ //must not crash; + ChangeEventWidget wid; + wid.ensurePolished(); + wid.setStyleSheet(" /* */ "); + wid.ensurePolished(); + wid.setStyleSheet(" /* ** */ "); + wid.ensurePolished(); +} + QTEST_MAIN(tst_QStyleSheetStyle) #include "tst_qstylesheetstyle.moc" -- cgit v0.12