Share SetupCRT with the unit tests so they can't pop a modal dialog

UnitTest.exe runs on CI and from tooling, where an assert or an abort() puts
up a message box that nothing will ever click, and the run just hangs until it
is killed. Headless already solved this; move its SetupCRT() into Common
(ExceptionHandlerSetup, which is where the rest of the process-level fault
setup lives) and call it from the unit tests too.

No behaviour change for headless. The OS-level SetErrorMode() call is now
guarded for UWP, which doesn't have it.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
This commit is contained in:
Henrik RydgårdandClaude Opus 5 committed 2026-08-17 13:11:16 +02:00
1 parent 0ac822d7f1
commit a96dfc1390
4 files changed
+42 -29

No files matched your search

+33
View File
@@ -20,9 +20,42 @@
#include "Common/MachineContext.h"
#include "Common/ExceptionHandlerSetup.h"
#if defined(_MSC_VER)
#include <crtdbg.h>
#include "Common/CommonWindows.h"
#endif
static BadAccessHandler g_badAccessHandler;
static void *altStack = nullptr;
void SetupCRT(bool suppressDialogs) {
#if defined(_MSC_VER)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
if (suppressDialogs) {
// 1. Redirect CRT assertions/errors/warnings to stderr.
const _HFILE reportTarget = _CRTDBG_FILE_STDERR;
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, reportTarget);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ERROR, reportTarget);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, reportTarget);
// 2. Suppress the abort() message box & crash reporting dialogs.
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#if !PPSSPP_PLATFORM(UWP)
// 3. Suppress Windows OS-level "Program has stopped working" modal dialogs.
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
#endif
}
#endif
}
#ifdef MACHINE_CONTEXT_SUPPORTED
// We cannot handle exceptions in UWP builds. Bleh.
+5
View File
@@ -21,3 +21,8 @@ void InstallExceptionHandler(BadAccessHandler accessHandler, bool logStackTraceO
// Implementation note: This must be a no-op if InstallExceptionHandler hasn't been called.
void UninstallExceptionHandler();
// MSVC-only, no-op elsewhere. Turns on the debug CRT's leak checking, and with suppressDialogs
// set, routes CRT assertions and abort() to stderr instead of a modal dialog - required for
// anything run non-interactively (headless, the unit tests, CI), where a dialog just hangs.
void SetupCRT(bool suppressDialogs);
+1 -29
View File
@@ -38,6 +38,7 @@
#include <csignal>
#endif
#include "Common/CPUDetect.h"
#include "Common/ExceptionHandlerSetup.h"
#include "Common/File/VFS/VFS.h"
#include "Common/File/VFS/ZipFileReader.h"
#include "Common/File/VFS/DirectoryReader.h"
@@ -520,35 +521,6 @@ public:
}
};
// Has a parameter because we might start using this from the main build.
void SetupCRT(bool headless) {
#if defined(_MSC_VER)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
if (headless) {
// Suppress abort dialogs and similar.
// 1. Redirect CRT Assertions/Errors/Warnings to stdout/stderr
const _HFILE reportTarget = _CRTDBG_FILE_STDERR;
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, reportTarget);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ERROR, reportTarget);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, reportTarget);
// 2. Suppress the abort() message box & crash reporting dialogs
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
// 3. Suppress Windows OS-level "Program has stopped working" modal dialogs
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
}
#endif
}
int main(int argc, const char* argv[]) {
PROFILE_INIT();
TimeInit();
+3
View File
@@ -77,6 +77,7 @@
#include "Common/ArmEmitter.h"
#include "Common/BitScan.h"
#include "Common/CPUDetect.h"
#include "Common/ExceptionHandlerSetup.h"
#include "Common/Log.h"
#include "Common/StringUtils.h"
#include "Core/Config.h"
@@ -1762,6 +1763,8 @@ TestItem availableTests[] = {
};
int main(int argc, const char *argv[]) {
// Never block on a modal dialog - these get run from CI and from tooling.
SetupCRT(true);
SetCurrentThreadName("UnitTest");
TimeInit();