mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-06-20 22:04:13 +02:00
Fix thread-unsafe QStandardPaths calls in dataDir/configDir
QStandardPaths::writableLocation() is not thread-safe in Qt5. ElementsCollectionModel::reload() launches: QtConcurrent::map(m_items_list_to_setUp, setUpData) Each worker calls FileElementCollectionItem::setUpData() → collectionPath() → isCollectionRoot() → QETApp::userMacrosDir() → QETApp::dataDir() → QStandardPaths::writableLocation() ← SIGSEGV (null deref) The crash was confirmed by Valgrind (address 0x0, inside libQt5Core's writableLocation internals). Fix: replace the bare QStandardPaths calls in dataDir() and configDir() with a C++11 static-local lambda. The compiler guarantees the lambda body runs exactly once across all threads (magic statics, ISO C++11 §6.7). After the first (main-thread) call the result is returned lock-free. Relates-to: #492 (same QtConcurrent lifetime pattern fixed in QETProject::writeBackup by PR #512).
This commit is contained in:
+16
-10
@@ -887,11 +887,14 @@ QString QETApp::configDir()
|
|||||||
#ifdef QET_ALLOW_OVERRIDE_CD_OPTION
|
#ifdef QET_ALLOW_OVERRIDE_CD_OPTION
|
||||||
if (config_dir != QString()) return(config_dir);
|
if (config_dir != QString()) return(config_dir);
|
||||||
#endif
|
#endif
|
||||||
QString configdir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
// C++11 static-local init runs exactly once across all threads — safe to
|
||||||
while (configdir.endsWith('/')) {
|
// call from QtConcurrent background threads (QStandardPaths is not).
|
||||||
configdir.remove(configdir.length()-1, 1);
|
static const QString cached = []() {
|
||||||
}
|
QString d = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
||||||
return configdir;
|
while (d.endsWith('/')) d.chop(1);
|
||||||
|
return d;
|
||||||
|
}();
|
||||||
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -911,11 +914,14 @@ QString QETApp::dataDir()
|
|||||||
#ifdef QET_ALLOW_OVERRIDE_DD_OPTION
|
#ifdef QET_ALLOW_OVERRIDE_DD_OPTION
|
||||||
if (data_dir != QString()) return(data_dir);
|
if (data_dir != QString()) return(data_dir);
|
||||||
#endif
|
#endif
|
||||||
QString datadir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
// C++11 static-local init runs exactly once across all threads — safe to
|
||||||
while (datadir.endsWith('/')) {
|
// call from QtConcurrent background threads (QStandardPaths is not).
|
||||||
datadir.remove(datadir.length()-1, 1);
|
static const QString cached = []() {
|
||||||
}
|
QString d = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||||
return datadir;
|
while (d.endsWith('/')) d.chop(1);
|
||||||
|
return d;
|
||||||
|
}();
|
||||||
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user