summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2020-08-01 11:11:41 -0400
committerGitHub <noreply@github.com>2020-08-01 11:11:41 -0400
commit592fa7310492392440ee73f4cc0f962c66d5aba7 (patch)
tree82d6fd20140acd8bbd9cbd9a953ac3c18019111e
parent9d3281fd58e41f4320f36710a1a36f9ece1efdc6 (diff)
parent64ba6cae1e6b74929d88de628bb2915cb9c6f2d2 (diff)
Merge pull request #1176 from isanae/2.3.1-fixes
2.3.1 fixes
-rw-r--r--src/envfs.h3
-rw-r--r--src/filetreeitem.cpp2
-rw-r--r--src/iconfetcher.cpp3
-rw-r--r--src/main.cpp30
-rw-r--r--src/organizercore.cpp8
-rw-r--r--src/thread_utils.h25
-rw-r--r--src/version.rc4
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