Skip to content

Commit 23ec6c9

Browse files
committed
Record the last fatal error message for crash reporting on Windows
1 parent 311c55f commit 23ec6c9

File tree

6 files changed

+112
-8
lines changed

6 files changed

+112
-8
lines changed

include/swift/Runtime/Debug.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ static inline const char *CRGetCrashLogMessage() {
6060
SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE
6161
static inline void CRSetCrashLogMessage(const char *) {}
6262

63+
#if defined(_WIN32)
64+
extern "C" {
65+
SWIFT_ATTRIBUTE_FOR_EXPORTS
66+
extern char* gLastFatalErrorMessage;
67+
}
68+
#endif // _WIN32
69+
6370
#endif
6471

6572
namespace swift {

stdlib/public/runtime/CrashReporter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,10 @@ struct crashreporter_annotations_t gCRAnnotations __attribute__((
3333
}
3434

3535
#endif
36+
37+
#if defined(_WIN32)
38+
extern "C" {
39+
SWIFT_ATTRIBUTE_FOR_EXPORTS
40+
char* gLastFatalErrorMessage = nullptr;
41+
}
42+
#endif

stdlib/public/runtime/Errors.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@
7070
#include "swift/Runtime/Atomic.h"
7171
#endif // SWIFT_HAVE_CRASHREPORTERCLIENT
7272

73+
#if defined(_WIN32)
74+
#include "swift/Runtime/Atomic.h"
75+
#endif // _WIN32
76+
7377
#include "BacktracePrivate.h"
7478

7579
namespace FatalErrorFlags {
@@ -268,16 +272,15 @@ void swift::printCurrentBacktrace(unsigned framesToSkip) {
268272
fprintf(stderr, "<backtrace unavailable>\n");
269273
}
270274

271-
// Report a message to any forthcoming crash log.
272-
static void
273-
reportOnCrash(uint32_t flags, const char *message)
274-
{
275-
#ifdef SWIFT_HAVE_CRASHREPORTERCLIENT
275+
#if defined(SWIFT_HAVE_CRASHREPORTERCLIENT) || defined(_WIN32)
276+
// Update the last fatal error message for crash reporting.
277+
static void updateLastFatalErrorMessage(void* location,
278+
const char* message) {
276279
char *oldMessage = nullptr;
277280
char *newMessage = nullptr;
278281

279282
oldMessage = std::atomic_load_explicit(
280-
(volatile std::atomic<char *> *)&gCRAnnotations.message,
283+
(volatile std::atomic<char *> *)location,
281284
SWIFT_MEMORY_ORDER_CONSUME);
282285

283286
do {
@@ -292,13 +295,25 @@ reportOnCrash(uint32_t flags, const char *message)
292295
newMessage = strdup(message);
293296
}
294297
} while (!std::atomic_compare_exchange_strong_explicit(
295-
(volatile std::atomic<char *> *)&gCRAnnotations.message,
298+
(volatile std::atomic<char *> *)location,
296299
&oldMessage, newMessage,
297300
std::memory_order_release,
298301
SWIFT_MEMORY_ORDER_CONSUME));
302+
}
303+
#endif // SWIFT_HAVE_CRASHREPORTERCLIENT || _WIN32
304+
305+
// Report a message to any forthcoming crash log.
306+
static void
307+
reportOnCrash(uint32_t flags, const char *message)
308+
{
309+
#ifdef SWIFT_HAVE_CRASHREPORTERCLIENT
310+
updateLastFatalErrorMessage(&gCRAnnotations.message, message);
311+
#elif defined(_WIN32)
312+
// Make the fatal error message accessible for Windows dump tools.
313+
updateLastFatalErrorMessage(&gLastFatalErrorMessage, message);
299314
#else
300315
// empty
301-
#endif // SWIFT_HAVE_CRASHREPORTERCLIENT
316+
#endif // SWIFT_HAVE_CRASHREPORTERCLIENT || _WIN32
302317
}
303318

304319
// Report a message to system console and stderr.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import WinSDK
2+
3+
func setupHandler() {
4+
SetUnhandledExceptionFilter { exception_pointers in
5+
guard let hSwiftCore = GetModuleHandleA("swiftCore.dll") else {
6+
return EXCEPTION_EXECUTE_HANDLER
7+
}
8+
guard let ppLastFatalErrorMessage = unsafeBitCast(
9+
GetProcAddress(hSwiftCore, "gLastFatalErrorMessage"),
10+
to: Optional<UnsafeMutablePointer<Optional<UnsafeMutablePointer<UInt8>>>>.self) else {
11+
return EXCEPTION_EXECUTE_HANDLER
12+
}
13+
guard let pLastFatalErrorMessage = ppLastFatalErrorMessage.pointee else {
14+
return EXCEPTION_EXECUTE_HANDLER
15+
}
16+
let message = "Fatal error message: \(String(cString: pLastFatalErrorMessage))"
17+
message.utf8CString.withUnsafeBufferPointer { buf in
18+
let addr = buf.baseAddress!
19+
let count = DWORD(buf.count)
20+
let stderr = GetStdHandle(STD_ERROR_HANDLE)
21+
WriteFile(stderr, addr, count, nil, nil)
22+
}
23+
return EXCEPTION_EXECUTE_HANDLER
24+
}
25+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s %S/Inputs/setup-handler-win.swift -o %t/a.out
3+
// RUN: %target-codesign %t/a.out
4+
// RUN: not %target-run %t/a.out 2>&1 | %FileCheck %s
5+
// REQUIRES: executable_test
6+
// REQUIRES: OS=windows-msvc
7+
8+
// CHECK: Fatal error message: a/fatal-error-message-win.swift:{{[0-9]+}}: Fatal error: Fatal crash!
9+
10+
func crash() {
11+
fatalError("Fatal crash!")
12+
}
13+
14+
@main
15+
struct Test {
16+
static func main() throws {
17+
setupHandler()
18+
crash()
19+
}
20+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s %S/Inputs/setup-handler-win.swift -o %t/a.out
3+
// RUN: %target-codesign %t/a.out
4+
// RUN: not %target-run %t/a.out 2>&1 | %FileCheck %s
5+
// REQUIRES: executable_test
6+
// REQUIRES: OS=windows-msvc
7+
8+
// CHECK: Fatal error message: a/fatal-try-error-message-win.swift:{{[0-9]+}}: Fatal error: 'try!' expression unexpectedly raised an error: a.Errs.getMyDescription("Try crash!")
9+
10+
enum Errs: Error {
11+
case getMyDescription(String)
12+
}
13+
14+
func throwings(_ i: Int) throws {
15+
if i == 0 {
16+
throw Errs.getMyDescription("Try crash!")
17+
}
18+
}
19+
20+
func crash() {
21+
try! throwings(0)
22+
}
23+
24+
@main
25+
struct Test {
26+
static func main() throws {
27+
setupHandler()
28+
crash()
29+
}
30+
}

0 commit comments

Comments
 (0)