summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Mutz <[email protected]>2025-03-22 18:26:46 +0100
committerMarc Mutz <[email protected]>2025-03-25 05:33:51 +0000
commit8b4900bffff3386e108847c9e1ffe9a15e05e5d3 (patch)
treee30d26f25e8c75e37b866481e376e7f2823b7915
parente72aea90fd82e81adac425e640cc9e8e6cd849cc (diff)
QMessageBox: fix UB (invalid cast) in Private::setVisible()
The function can be called from ~QDialog(), in which case a cast of q_ptr to QMessageBox is UB. Says UBSan: qmessagebox.cpp:182:5: runtime error: downcast of address 0x7ffdccfbda00 which does not point to an object of type 'QMessageBox' 0x7ffdccfbda00: note: object is of type 'QDialog' 88 7f 00 00 30 94 4a 73 88 7f 00 00 80 8c 00 00 90 61 00 00 08 96 4a 73 88 7f 00 00 00 00 fb cc ^~~~~~~~~~~~~~~~~~~~~~~ vptr for 'QDialog' #0 0x7f8870f9a8a3 in QMessageBoxPrivate::q_func() qmessagebox.cpp:182 #1 0x7f8870f9a8a3 in QMessageBoxPrivate::setVisible(bool) qmessagebox.cpp:1660 #2 0x7f8870c6b3b5 in QDialog::setVisible(bool) qdialog.cpp:757 #3 0x7f886e4ad4b8 in QWidget::hide() qwidget.cpp:8179 #4 0x7f8870c6abc9 in QDialog::~QDialog() qdialog.cpp:398 Fix by casting to QMessageBox only on show(), not hide(), and otherwise cast at most to QDialog* (QWidget* actually suffices). Add a code comment. Amends e0bb9e81ab1a9d71f2893844ea82430467422e21 (I think; it might have been present in a different form before that). Pick-to: 6.9 6.8 6.5 Change-Id: Ia163483c1998924a0d9c9fd589311af24a93d1fe Reviewed-by: Axel Spoerl <[email protected]>
-rw-r--r--src/widgets/dialogs/qmessagebox.cpp15
1 files changed, 9 insertions, 6 deletions
diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp
index df17399ca7e..f9d58e4d906 100644
--- a/src/widgets/dialogs/qmessagebox.cpp
+++ b/src/widgets/dialogs/qmessagebox.cpp
@@ -1657,12 +1657,15 @@ void QMessageBox::open(QObject *receiver, const char *member)
void QMessageBoxPrivate::setVisible(bool visible)
{
- Q_Q(QMessageBox);
-
// Last minute setup
- if (autoAddOkButton)
- q->addButton(QMessageBox::Ok);
- detectEscapeButton();
+ if (visible) {
+ Q_Q(QMessageBox);
+ if (autoAddOkButton)
+ q->addButton(QMessageBox::Ok);
+ detectEscapeButton();
+ }
+ // On hide, we may be called from ~QDialog(), so prevent accessing
+ // q_ptr as a QMessageBox!
if (canBeNativeDialog())
setNativeDialogVisible(visible);
@@ -1670,7 +1673,7 @@ void QMessageBoxPrivate::setVisible(bool visible)
// Update WA_DontShowOnScreen based on whether the native dialog was shown,
// so that QDialog::setVisible(visible) below updates the QWidget state correctly,
// but skips showing the non-native version.
- q->setAttribute(Qt::WA_DontShowOnScreen, nativeDialogInUse);
+ static_cast<QWidget*>(q_ptr)->setAttribute(Qt::WA_DontShowOnScreen, nativeDialogInUse);
QDialogPrivate::setVisible(visible);
}