diff --git a/llvm/lib/Support/Windows/Signals.inc b/llvm/lib/Support/Windows/Signals.inc --- a/llvm/lib/Support/Windows/Signals.inc +++ b/llvm/lib/Support/Windows/Signals.inc @@ -159,6 +159,10 @@ typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); static fpEnumerateLoadedModules fEnumerateLoadedModules; +static bool isDebugHelpInitialized() { + return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; +} + static bool load64BitDebugHelp(void) { HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); if (hLib) { @@ -181,7 +185,7 @@ fEnumerateLoadedModules = (fpEnumerateLoadedModules) ::GetProcAddress(hLib, "EnumerateLoadedModules64"); } - return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; + return isDebugHelpInitialized(); } using namespace llvm; @@ -296,6 +300,12 @@ static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, HANDLE hThread, STACKFRAME64 &StackFrame, CONTEXT *Context) { + // It's possible that DbgHelp.dll hasn't been loaded yet (e.g. if this + // function is called before the main program called `llvm::InitLLVM`). + // In this case just return, not stacktrace will be printed. + if (!isDebugHelpInitialized()) + return; + // Initialize the symbol handler. fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); fSymInitialize(hProcess, NULL, TRUE); diff --git a/llvm/unittests/Support/ProgramTest.cpp b/llvm/unittests/Support/ProgramTest.cpp --- a/llvm/unittests/Support/ProgramTest.cpp +++ b/llvm/unittests/Support/ProgramTest.cpp @@ -12,6 +12,7 @@ #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Signals.h" #include "gtest/gtest.h" #include #include @@ -426,4 +427,28 @@ sys::fs::remove(LockedFile); } +TEST_F(ProgramEnvTest, TestExecuteWithNoStacktraceHandler) { + using namespace llvm::sys; + + if (getenv("LLVM_PROGRAM_TEST_NO_STACKTRACE_HANDLER")) { + sys::PrintStackTrace(errs()); + exit(0); + } + + std::string Executable = + sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1); + StringRef argv[] = { + Executable, + "--gtest_filter=ProgramEnvTest.TestExecuteWithNoStacktraceHandler"}; + + addEnvVar("LLVM_PROGRAM_TEST_NO_STACKTRACE_HANDLER=1"); + + std::string Error; + bool ExecutionFailed; + int RetCode = ExecuteAndWait(Executable, argv, getEnviron(), {}, 0, 0, &Error, + &ExecutionFailed); + EXPECT_FALSE(ExecutionFailed) << Error; + ASSERT_EQ(0, RetCode); +} + } // end anonymous namespace diff --git a/llvm/utils/unittest/UnitTestMain/TestMain.cpp b/llvm/utils/unittest/UnitTestMain/TestMain.cpp --- a/llvm/utils/unittest/UnitTestMain/TestMain.cpp +++ b/llvm/utils/unittest/UnitTestMain/TestMain.cpp @@ -10,6 +10,7 @@ #include "llvm/Support/Signals.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include #if defined(_WIN32) # include @@ -21,8 +22,12 @@ const char *TestMainArgv0; int main(int argc, char **argv) { - llvm::sys::PrintStackTraceOnErrorSignal(argv[0], - true /* Disable crash reporting */); + // Skip setting up signal handlers for tests that need to test things without + // them configured. + if (!getenv("LLVM_PROGRAM_TEST_NO_STACKTRACE_HANDLER")) { + llvm::sys::PrintStackTraceOnErrorSignal(argv[0], + true /* Disable crash reporting */); + } // Initialize both gmock and gtest. testing::InitGoogleMock(&argc, argv);