diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2020-08-01 11:11:41 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-08-01 11:11:41 -0400 |
| commit | 592fa7310492392440ee73f4cc0f962c66d5aba7 (patch) | |
| tree | 82d6fd20140acd8bbd9cbd9a953ac3c18019111e | |
| parent | 9d3281fd58e41f4320f36710a1a36f9ece1efdc6 (diff) | |
| parent | 64ba6cae1e6b74929d88de628bb2915cb9c6f2d2 (diff) | |
Merge pull request #1176 from isanae/2.3.1-fixes
2.3.1 fixes
| -rw-r--r-- | src/envfs.h | 3 | ||||
| -rw-r--r-- | src/filetreeitem.cpp | 2 | ||||
| -rw-r--r-- | src/iconfetcher.cpp | 3 | ||||
| -rw-r--r-- | src/main.cpp | 30 | ||||
| -rw-r--r-- | src/organizercore.cpp | 8 | ||||
| -rw-r--r-- | src/thread_utils.h | 25 | ||||
| -rw-r--r-- | src/version.rc | 4 |
7 files changed, 59 insertions, 16 deletions
diff --git a/src/envfs.h b/src/envfs.h index bbc27005..e4d98d71 100644 --- a/src/envfs.h +++ b/src/envfs.h @@ -1,6 +1,7 @@ #ifndef ENV_ENVFS_H #define ENV_ENVFS_H +#include "thread_utils.h" #include <thread> namespace env @@ -125,7 +126,7 @@ private: ThreadInfo() : busy(true), ready(false), stop(false) { - thread = std::thread([&]{ run(); }); + thread = MOShared::startSafeThread([&]{ run(); }); } ~ThreadInfo() diff --git a/src/filetreeitem.cpp b/src/filetreeitem.cpp index 49bc65ac..7997974f 100644 --- a/src/filetreeitem.cpp +++ b/src/filetreeitem.cpp @@ -40,7 +40,7 @@ const QString& directoryFileType() const QString& cachedFileTypeNoExtension() { static const QString name = [] { - const DWORD flags = SHGFI_TYPENAME; + const DWORD flags = SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES; SHFILEINFOW sfi = {}; // dummy filename with no extension diff --git a/src/iconfetcher.cpp b/src/iconfetcher.cpp index 129be50e..c10adc8d 100644 --- a/src/iconfetcher.cpp +++ b/src/iconfetcher.cpp @@ -1,4 +1,5 @@ #include "iconfetcher.h" +#include "thread_utils.h" #include "shared/util.h" void IconFetcher::Waiter::wait() @@ -25,7 +26,7 @@ IconFetcher::IconFetcher() m_quickCache.file = getPixmapIcon(QFileIconProvider::File); m_quickCache.directory = getPixmapIcon(QFileIconProvider::Folder); - m_thread = std::thread([&]{ threadFun(); }); + m_thread = MOShared::startSafeThread([&]{ threadFun(); }); } IconFetcher::~IconFetcher() diff --git a/src/main.cpp b/src/main.cpp index 46f2f0aa..f008896b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -127,9 +127,9 @@ bool bootstrap() return true; } -LPTOP_LEVEL_EXCEPTION_FILTER prevUnhandledExceptionFilter = nullptr; +thread_local LPTOP_LEVEL_EXCEPTION_FILTER prevUnhandledExceptionFilter = nullptr; -static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs) +LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs) { const std::wstring& dumpPath = OrganizerCore::crashDumpsPath(); int dumpRes = @@ -139,12 +139,33 @@ static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *except else log::error("ModOrganizer has crashed, CreateMiniDump failed ({}, error {}).", dumpRes, GetLastError()); - if (prevUnhandledExceptionFilter) + if (prevUnhandledExceptionFilter && exceptionPtrs) return prevUnhandledExceptionFilter(exceptionPtrs); else return EXCEPTION_CONTINUE_SEARCH; } +void terminateHandler() noexcept +{ + __try + { + // force an exception to get a valid stack trace for this thread + *(int*)0 = 42; + } + __except + ( + MyUnhandledExceptionFilter(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER + ) + { + } +} + +void setUnhandledExceptionHandler() +{ + prevUnhandledExceptionFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); + std::set_terminate(terminateHandler); +} + // Parses the first parseArgCount arguments of the current process command line and returns // them in parsedArgs, the rest of the command line is returned untouched. LPCWSTR UntouchedCommandLineArguments(int parseArgCount, std::vector<std::wstring>& parsedArgs) @@ -171,6 +192,7 @@ LPCWSTR UntouchedCommandLineArguments(int parseArgCount, std::vector<std::wstrin return cmd; } + static int SpawnWaitProcess(LPCWSTR workingDirectory, LPCWSTR commandLine) { PROCESS_INFORMATION pi{ 0 }; STARTUPINFO si{ 0 }; @@ -947,7 +969,7 @@ int main(int argc, char *argv[]) application.setProperty("dataPath", dataPath); // initialize dump collection only after "dataPath" since the crashes are stored under it - prevUnhandledExceptionFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); + setUnhandledExceptionHandler(); const auto logFile = qApp->property("dataPath").toString() + "/logs/mo_interface.log"; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 062369d6..1e2a0aa1 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -221,7 +221,7 @@ void OrganizerCore::updateExecutablesList() void OrganizerCore::updateModInfoFromDisc() { ModInfo::updateFromDisc( m_Settings.paths().mods(), &m_DirectoryStructure, - m_PluginContainer, m_Settings.interface().displayForeign(), + m_PluginContainer, m_Settings.interface().displayForeign(), m_Settings.refreshThreadCount(), managedGame()); } @@ -371,7 +371,7 @@ void OrganizerCore::downloadRequestedNXM(const QString &url) } } -void OrganizerCore::userInterfaceInitialized() +void OrganizerCore::userInterfaceInitialized() { m_UserInterfaceInitialized(m_UserInterface->mainWindow()); } @@ -1139,7 +1139,7 @@ void OrganizerCore::refreshModList(bool saveChanges) ModInfo::updateFromDisc( m_Settings.paths().mods(), &m_DirectoryStructure, - m_PluginContainer, m_Settings.interface().displayForeign(), + m_PluginContainer, m_Settings.interface().displayForeign(), m_Settings.refreshThreadCount(), managedGame()); m_CurrentProfile->refreshModStatus(); @@ -1473,7 +1473,7 @@ void OrganizerCore::directory_refreshed() m_StructureDeleter.join(); } - m_StructureDeleter = std::thread([=]{ + m_StructureDeleter = MOShared::startSafeThread([=]{ log::debug("structure deleter thread start"); delete newStructure; log::debug("structure deleter thread done"); diff --git a/src/thread_utils.h b/src/thread_utils.h index f0067b6a..607d73a9 100644 --- a/src/thread_utils.h +++ b/src/thread_utils.h @@ -1,12 +1,31 @@ #ifndef MO2_THREAD_UTILS_H #define MO2_THREAD_UTILS_H +#include <log.h> #include <functional> #include <mutex> #include <thread> +// in main.cpp +void setUnhandledExceptionHandler(); +LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs); + + namespace MOShared { +// starts an std::thread with an unhandled exception handler for core dumps +// and a top-level catch +// +template <class F> +std::thread startSafeThread(F&& f) +{ + return std::thread([f=std::forward<F>(f)] { + setUnhandledExceptionHandler(); + f(); + }); +} + + /** * Class that can be used to perform thread-safe memoization. * @@ -26,7 +45,7 @@ struct MemoizedLocked { template <class Callable> MemoizedLocked(Callable &&callable, T value = {}) : m_Fn{ std::forward<Callable>(callable) }, m_Value{ std::move(value) } { } - + template <class... Args> T& value(Args&&... args) const { if (m_NeedUpdating) { @@ -66,7 +85,7 @@ private: * */ template <class It, class Callable> -void parallelMap(It begin, It end, Callable callable, std::size_t nThreads) +void parallelMap(It begin, It end, Callable callable, std::size_t nThreads) { std::mutex m; std::vector<std::thread> threads(nThreads); @@ -75,7 +94,7 @@ void parallelMap(It begin, It end, Callable callable, std::size_t nThreads) // - The mutex is only used to fetch/increment the iterator. // - The callable is copied in each thread to avoid conflicts. for (auto &thread: threads) { - thread = std::thread([&m, &begin, end, callable]() { + thread = startSafeThread([&m, &begin, end, callable]() { while (true) { decltype(begin) it; { diff --git a/src/version.rc b/src/version.rc index b4dff388..8e2000ed 100644 --- a/src/version.rc +++ b/src/version.rc @@ -3,8 +3,8 @@ // If VS_FF_PRERELEASE is not set, MO labels the build as a release and uses VER_FILEVERSION to determine version number. // Otherwise, if letters are used in VER_FILEVERSION_STR, uses the full MOBase::VersionInfo parser // Otherwise, uses the numbers from VER_FILEVERSION and sets the release type as pre-alpha -#define VER_FILEVERSION 2,3,0 -#define VER_FILEVERSION_STR "2.3.0\0" +#define VER_FILEVERSION 2,3,1 +#define VER_FILEVERSION_STR "2.3.1\0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION |
