Skip to content

Conversation

hebasto
Copy link
Member

@hebasto hebasto commented Jan 19, 2020

The code, the bool* ret = nullptr parameter in the BitcoinGUI::message() slot, removed in #17943 is not dead actually. It is used in ThreadSafeMessageBox() function:

bitcoin/src/qt/bitcoingui.cpp

Lines 1363 to 1368 in a654626

bool invoked = QMetaObject::invokeMethod(gui, "message",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)),
Q_ARG(unsigned int, style),
Q_ARG(bool*, &ret));

Now in master (a654626):

$ ./src/qt/bitcoin-qt -prune=-1
Error: Prune cannot be configured with a negative value.
bitcoin-qt: qt/bitcoingui.cpp:1369: bool ThreadSafeMessageBox(BitcoinGUI*, const string&, const string&, unsigned int): Assertion `invoked' failed.
Aborted (core dumped)

This PR reverts all commits of #17943

Additional notes: the bug was missed due to dynamic function call QMetaObject::invokeMethod() which cannot be checked at compile time. See #16348 for more discussion.

Sorry for introducing a bug.

@fanquake fanquake added the GUI label Jan 19, 2020
@fanquake fanquake requested review from Empact, promag and Sjors January 19, 2020 08:05
@Sjors
Copy link
Member

Sjors commented Jan 19, 2020

ACK 70e4706

From #16348:

Once we bump Qt to at least 5.10 these can be refactored to use the invokeMethod overload that allows connecting to lambdas or member pointers, which are compile checked.

From #13478:

Qt Versions:

5.12 (LTS) Supported for 3 years post release.
5.11 Supported until May 2019
5.10 Supported until Dec 2018 (Archived).
5.9 (LTS) Supported until May 31, 2020.
5.6 (LTS) Supported until Mar. 16, 2019 (will end around the same time as the v0.18.0 release).

Any other releases older than 5.10 are no longer supported (by Qt).

Qt releases seem to be getting more frequent, and in some cases more aggressive about dropping support for OS versions. i.e macOS >10.12 is required for Qt 5.12.

It might be a good idea to bump the minimum version to 5.12 after the 0.20 branch-off. Alternatively we could duplicate the code with #IF QT_VERSION >= 0x051000 with the modern syntax, so that the compiler will catch an accidental refactor bug like this.

@promag
Copy link
Contributor

promag commented Jan 19, 2020

I think we should fix ThreadSafeMessageBox instead. Note that if modal == false Qt::QueuedConnection is used and a pointer to the local ret is passed, which goes out of scope. So by the time slot message is called it dereferences an invalid pointer. Please correct me if I'm wrong.

@hebasto
Copy link
Member Author

hebasto commented Jan 19, 2020

I think we should fix ThreadSafeMessageBox instead. Note that if modal == false Qt::QueuedConnection is used and a pointer to the local ret is passed, which goes out of scope. So by the time slot message is called it dereferences an invalid pointer. Please correct me if I'm wrong.

QMetaObject::invokeMethod() passes 4 arguments to BitcoinGUI::message() with 3 parameters signature.

@promag
Copy link
Contributor

promag commented Jan 19, 2020

@hebasto I mean that if we merge this then the problem above exists.

@hebasto
Copy link
Member Author

hebasto commented Jan 19, 2020

@promag

Note that if modal == false Qt::QueuedConnection is used and a pointer to the local ret is passed, which goes out of scope. So by the time slot message is called it dereferences an invalid pointer.

Indeed.

@hebasto
Copy link
Member Author

hebasto commented Jan 19, 2020

I think we should fix ThreadSafeMessageBox instead.

I found the only place where return value is used:

bitcoin/src/init.cpp

Lines 1614 to 1617 in a654626

bool fRet = uiInterface.ThreadSafeQuestion(
strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?").translated,
strLoadError + ".\nPlease restart with -reindex or -reindex-chainstate to recover.",
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);

Could we replace our custom ThreadSafeMessageBox with standard QMessageBox here?

@DrahtBot
Copy link
Contributor

DrahtBot commented Jan 19, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #17966 (qt, refactor: Optimize signal-slot connections logic by hebasto)
  • #17937 (gui: Remove WalletView and BitcoinGUI circular dependency by promag)
  • #16224 (gui: Bilingual GUI error messages by hebasto)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@laanwj
Copy link
Member

laanwj commented Jan 19, 2020

I'm happy this was discovered before a release! Please do be careful with cleanup changes like this.

@hebasto
Copy link
Member Author

hebasto commented Jan 19, 2020

@promag how about this patch to master:

diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 6043e93f9..ea13b60c2 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -1025,7 +1025,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
     progressBar->setToolTip(tooltip);
 }
 
-void BitcoinGUI::message(const QString& title, QString message, unsigned int style)
+bool BitcoinGUI::message(const QString& title, QString message, unsigned int style)
 {
     // Default title. On macOS, the window title is ignored (as required by the macOS Guidelines).
     QString strTitle{PACKAGE_NAME};
@@ -1079,9 +1079,10 @@ void BitcoinGUI::message(const QString& title, QString message, unsigned int sty
         showNormalIfMinimized();
         QMessageBox mBox(static_cast<QMessageBox::Icon>(nMBoxIcon), strTitle, message, buttons, this);
         mBox.setTextFormat(Qt::PlainText);
-        mBox.exec();
+        return mBox.exec() == QMessageBox::Ok;
     } else {
         notificator->notify(static_cast<Notificator::Class>(nNotifyIcon), strTitle, message);
+        return false;
     }
 }
 
@@ -1362,10 +1363,10 @@ static bool ThreadSafeMessageBox(BitcoinGUI* gui, const std::string& message, co
     // In case of modal message, use blocking connection to wait for user to click a button
     bool invoked = QMetaObject::invokeMethod(gui, "message",
                                modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
+                               Q_RETURN_ARG(bool, ret),
                                Q_ARG(QString, QString::fromStdString(caption)),
                                Q_ARG(QString, QString::fromStdString(message)),
-                               Q_ARG(unsigned int, style),
-                               Q_ARG(bool*, &ret));
+                               Q_ARG(unsigned int, style));
     assert(invoked);
     return ret;
 }
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 45fbb03aa..53c9e750b 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -219,8 +219,9 @@ public Q_SLOTS:
        @param[in] message   the displayed text
        @param[in] style     modality and style definitions (icon and used buttons - buttons only for message boxes)
                             @see CClientUIInterface::MessageBoxFlags
+       @return True if Ok was clicked (modal only)
     */
-    void message(const QString& title, QString message, unsigned int style);
+    bool message(const QString& title, QString message, unsigned int style);
 
 #ifdef ENABLE_WALLET
     void setCurrentWallet(WalletModel* wallet_model);

From Qt docs:

If the invocation is asynchronous, the return value cannot be evaluated.

@hebasto
Copy link
Member Author

hebasto commented Jan 19, 2020

Also I did not find any ThreadSafeMessageBox() invocation without CClientUIInterface::MODAL set.

@jonasschnelli
Copy link
Contributor

Thanks for fixing.
Sorry for not testing #17943.
I think GUI refactoring should not be taken too easy since there are little tests that would detect possible new issues.

@laanwj
Copy link
Member

laanwj commented Jan 20, 2020

I think GUI refactoring should not be taken too easy since there are little tests that would detect possible new issues.

Agree.

@laanwj
Copy link
Member

laanwj commented Jan 22, 2020

I reverted the commits from this PR and got exactly the same.
ACK 70e4706

laanwj added a commit that referenced this pull request Jan 22, 2020
70e4706 Revert "refactor: Remove never used default parameter" (Hennadii Stepanov)
219417b Revert "refactor: Simplify connection syntax" (Hennadii Stepanov)

Pull request description:

  The code, the `bool* ret = nullptr` parameter in the `BitcoinGUI::message()` slot, removed in #17943 is not dead actually. It is used in `ThreadSafeMessageBox()` function:
  https://github.com/bitcoin/bitcoin/blob/a654626f076a72416a3d354218d7107571d6caaf/src/qt/bitcoingui.cpp#L1363-L1368

  Now in master (a654626):
  ```
  $ ./src/qt/bitcoin-qt -prune=-1
  Error: Prune cannot be configured with a negative value.
  bitcoin-qt: qt/bitcoingui.cpp:1369: bool ThreadSafeMessageBox(BitcoinGUI*, const string&, const string&, unsigned int): Assertion `invoked' failed.
  Aborted (core dumped)
  ```

  This PR reverts all commits of #17943

  Additional notes: the bug was missed due to dynamic function call `QMetaObject::invokeMethod()` which cannot be checked at compile time. See #16348 for more discussion.

  Sorry for introducing a bug.

ACKs for top commit:
  Sjors:
    ACK 70e4706
  laanwj:
    ACK 70e4706

Tree-SHA512: b968a026eaa4f5f39fd36ddc715d8e233f3c6420e6580f11d4ca422a5ff5d1d9d3df9ac11b353c3d4f434d67d6a69e37d2e26b8248d72bedd14ecba0a545a327
@laanwj laanwj merged commit 70e4706 into bitcoin:master Jan 22, 2020
@Empact
Copy link
Contributor

Empact commented Jan 22, 2020

Post-hoc ACK 70e4706

And partial mea culpa: if I had looked more closely at 35ecf85 which I cited here I would have seen that it had been moved and retained and continued to follow it to its current location.

@hebasto hebasto deleted the 20200119-revert17943 branch January 31, 2020 16:37
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Dec 22, 2021
70e4706 Revert "refactor: Remove never used default parameter" (Hennadii Stepanov)
219417b Revert "refactor: Simplify connection syntax" (Hennadii Stepanov)

Pull request description:

  The code, the `bool* ret = nullptr` parameter in the `BitcoinGUI::message()` slot, removed in bitcoin#17943 is not dead actually. It is used in `ThreadSafeMessageBox()` function:
  https://github.com/bitcoin/bitcoin/blob/a654626f076a72416a3d354218d7107571d6caaf/src/qt/bitcoingui.cpp#L1363-L1368

  Now in master (a654626):
  ```
  $ ./src/qt/bitcoin-qt -prune=-1
  Error: Prune cannot be configured with a negative value.
  bitcoin-qt: qt/bitcoingui.cpp:1369: bool ThreadSafeMessageBox(BitcoinGUI*, const string&, const string&, unsigned int): Assertion `invoked' failed.
  Aborted (core dumped)
  ```

  This PR reverts all commits of bitcoin#17943

  Additional notes: the bug was missed due to dynamic function call `QMetaObject::invokeMethod()` which cannot be checked at compile time. See bitcoin#16348 for more discussion.

  Sorry for introducing a bug.

ACKs for top commit:
  Sjors:
    ACK 70e4706
  laanwj:
    ACK 70e4706

Tree-SHA512: b968a026eaa4f5f39fd36ddc715d8e233f3c6420e6580f11d4ca422a5ff5d1d9d3df9ac11b353c3d4f434d67d6a69e37d2e26b8248d72bedd14ecba0a545a327
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Dec 22, 2021
70e4706 Revert "refactor: Remove never used default parameter" (Hennadii Stepanov)
219417b Revert "refactor: Simplify connection syntax" (Hennadii Stepanov)

Pull request description:

  The code, the `bool* ret = nullptr` parameter in the `BitcoinGUI::message()` slot, removed in bitcoin#17943 is not dead actually. It is used in `ThreadSafeMessageBox()` function:
  https://github.com/bitcoin/bitcoin/blob/a654626f076a72416a3d354218d7107571d6caaf/src/qt/bitcoingui.cpp#L1363-L1368

  Now in master (a654626):
  ```
  $ ./src/qt/bitcoin-qt -prune=-1
  Error: Prune cannot be configured with a negative value.
  bitcoin-qt: qt/bitcoingui.cpp:1369: bool ThreadSafeMessageBox(BitcoinGUI*, const string&, const string&, unsigned int): Assertion `invoked' failed.
  Aborted (core dumped)
  ```

  This PR reverts all commits of bitcoin#17943

  Additional notes: the bug was missed due to dynamic function call `QMetaObject::invokeMethod()` which cannot be checked at compile time. See bitcoin#16348 for more discussion.

  Sorry for introducing a bug.

ACKs for top commit:
  Sjors:
    ACK 70e4706
  laanwj:
    ACK 70e4706

Tree-SHA512: b968a026eaa4f5f39fd36ddc715d8e233f3c6420e6580f11d4ca422a5ff5d1d9d3df9ac11b353c3d4f434d67d6a69e37d2e26b8248d72bedd14ecba0a545a327
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Dec 22, 2021
70e4706 Revert "refactor: Remove never used default parameter" (Hennadii Stepanov)
219417b Revert "refactor: Simplify connection syntax" (Hennadii Stepanov)

Pull request description:

  The code, the `bool* ret = nullptr` parameter in the `BitcoinGUI::message()` slot, removed in bitcoin#17943 is not dead actually. It is used in `ThreadSafeMessageBox()` function:
  https://github.com/bitcoin/bitcoin/blob/a654626f076a72416a3d354218d7107571d6caaf/src/qt/bitcoingui.cpp#L1363-L1368

  Now in master (a654626):
  ```
  $ ./src/qt/bitcoin-qt -prune=-1
  Error: Prune cannot be configured with a negative value.
  bitcoin-qt: qt/bitcoingui.cpp:1369: bool ThreadSafeMessageBox(BitcoinGUI*, const string&, const string&, unsigned int): Assertion `invoked' failed.
  Aborted (core dumped)
  ```

  This PR reverts all commits of bitcoin#17943

  Additional notes: the bug was missed due to dynamic function call `QMetaObject::invokeMethod()` which cannot be checked at compile time. See bitcoin#16348 for more discussion.

  Sorry for introducing a bug.

ACKs for top commit:
  Sjors:
    ACK 70e4706
  laanwj:
    ACK 70e4706

Tree-SHA512: b968a026eaa4f5f39fd36ddc715d8e233f3c6420e6580f11d4ca422a5ff5d1d9d3df9ac11b353c3d4f434d67d6a69e37d2e26b8248d72bedd14ecba0a545a327
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Dec 28, 2021
70e4706 Revert "refactor: Remove never used default parameter" (Hennadii Stepanov)
219417b Revert "refactor: Simplify connection syntax" (Hennadii Stepanov)

Pull request description:

  The code, the `bool* ret = nullptr` parameter in the `BitcoinGUI::message()` slot, removed in bitcoin#17943 is not dead actually. It is used in `ThreadSafeMessageBox()` function:
  https://github.com/bitcoin/bitcoin/blob/a654626f076a72416a3d354218d7107571d6caaf/src/qt/bitcoingui.cpp#L1363-L1368

  Now in master (a654626):
  ```
  $ ./src/qt/bitcoin-qt -prune=-1
  Error: Prune cannot be configured with a negative value.
  bitcoin-qt: qt/bitcoingui.cpp:1369: bool ThreadSafeMessageBox(BitcoinGUI*, const string&, const string&, unsigned int): Assertion `invoked' failed.
  Aborted (core dumped)
  ```

  This PR reverts all commits of bitcoin#17943

  Additional notes: the bug was missed due to dynamic function call `QMetaObject::invokeMethod()` which cannot be checked at compile time. See bitcoin#16348 for more discussion.

  Sorry for introducing a bug.

ACKs for top commit:
  Sjors:
    ACK 70e4706
  laanwj:
    ACK 70e4706

Tree-SHA512: b968a026eaa4f5f39fd36ddc715d8e233f3c6420e6580f11d4ca422a5ff5d1d9d3df9ac11b353c3d4f434d67d6a69e37d2e26b8248d72bedd14ecba0a545a327
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Feb 15, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants