qt: Fix random segfault when closing "Choose data directory" dialog 364/head
authorWladimir J. van der Laan <laanwj@gmail.com>
Thu, 18 Aug 2016 14:58:04 +0000 (16:58 +0200)
committersvost <ya.nowa@yandex.ru>
Mon, 30 Jan 2017 16:18:00 +0000 (19:18 +0300)
The `pickDataDirectory()` function was calling `exit(0)` to quit
the application when the user closes the dialog without choosing
a data directory.

This is a bad idea because a background thread is created (to
check free space on the drive of the currently selected datadir).
The thread is not stopped and unwound properly, resulting in a potential
race condition somewhere deep in Qt.

So replace the `exit()` by a boolean return value, and let the
stack unwind normally.

src/qt/bitcoin.cpp
src/qt/intro.cpp
src/qt/intro.h

index f99ee0f..7e73504 100644 (file)
@@ -176,7 +176,8 @@ int main(int argc, char *argv[])
     ParseParameters(argc, argv);
 
     // User language is set up: pick a data directory
-    Intro::pickDataDirectory();
+    if (!Intro::pickDataDirectory())
+        return 0;
 
     // Install global event filter that makes sure that long tooltips can be word-wrapped
     app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
index 75c1c82..6da9833 100644 (file)
@@ -149,14 +149,14 @@ QString Intro::getDefaultDataDirectory()
     return GUIUtil::boostPathToQString(GetDefaultDataDir());
 }
 
-void Intro::pickDataDirectory()
+bool Intro::pickDataDirectory()
 {
     namespace fs = boost::filesystem;
     QSettings settings;
     /* If data directory provided on command line, no need to look at settings
        or show a picking dialog */
     if(!GetArg("-datadir", "").empty())
-        return;
+        return true;
     /* 1) Default data directory for operating system */
     QString dataDir = getDefaultDataDirectory();
     /* 2) Allow QSettings to override default dir */
@@ -174,7 +174,7 @@ void Intro::pickDataDirectory()
             if(!intro.exec())
             {
                 /* Cancel clicked */
-                exit(0);
+                return false;
             }
             dataDir = intro.getDataDirectory();
             try {
@@ -195,6 +195,7 @@ void Intro::pickDataDirectory()
      */
     if(dataDir != getDefaultDataDirectory())
         SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
+    return true;
 }
 
 void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable)
index c973561..dd9eb5b 100644 (file)
@@ -33,10 +33,13 @@ public:
     /**
      * Determine data directory. Let the user choose if the current one doesn't exist.
      *
+     * @returns true if a data directory was selected, false if the user cancelled the selection
+     * dialog.
+     *
      * @note do NOT call global GetDataDir() before calling this function, this
      * will cause the wrong path to be cached.
      */
-    static void pickDataDirectory();
+    static bool pickDataDirectory();
 
     /**
      * Determine default data directory for operating system.