Print stack trace for fatalError

This is a simple proposal:

I think fatalError should dump a stack trace the same way NSExceptions do. In Xcode and lldb, we have the ability to view the stack trace at a given execution location. However, it's so much simpler to just print a stack trace when running outside of a debugger (at least when compiled in debug mode) that it'd help us tremendously when trying to fix bugs in Swift projects developed outside of Xcode.

For example, I'm working with a library and I have no idea what line in anything caused an optional unwrap. All I see is:

fatalError: unexpectedly found nil when unwrapping optional value

Thoughts?

- Harlan

8 Likes

We have this problem with test cases that result in fatalErrors as well, sometimes if it's in test setup code it's hard to trace back to the actual class / test case

1 Like

This would be a huge win for those of us doing Linux work. Also has a lot of precedence in other languages.

3 Likes

Very much agreed and itโ€™s something weโ€™ve been looking at and have interest in esp as the server libraries folks... until an official answer and/or solution pops up in Swift itself this library can get you almost there: https://github.com/ianpartridge/swift-backtrace

// sorry for briefity, texted from skiing :slight_smile:

If you build in debug mode, then the error message should also include source location info. (Maybe we should include the source location info in the trap message for release builds as well.) And if you have line tables, the trap instruction should have with a source location that you could trace back to the operation that trapped. In top-of-tree compilers, this trap instruction is also put in an artificial inline frame with a function name that describes the trap reason; I don't think that it's advanced enough yet to include "fatalError" strings, though we should eventually be able to do so using constant evaluation of strings.

2 Likes

Did we explicitly disable fatalError backtraces? They should be working now on all platforms except Cygwin and Haiku...

I'm not sure, but on Darwin at least, it could have been considered to be redundant since the system crash reporter generates backtraces already. On Linux platforms, I also recall there being problems with in-process symbolication, since the glibc backtrace functions fail to find symbols except in rather narrow circumstances, so the printed backtraces weren't very useful.

The problem we hit with this is that you don't get these stack traces in tests. So if you call a function that ends up calling fatalError you see the line of the fatalError, but that may not be helpful. Here's the example output from a fresh swiftpm package on macOS:

% swift test
[3/3] Linking fatalPackageTests
Test Suite 'All tests' started at 2020-01-09 17:15:59.243
Test Suite 'fatalPackageTests.xctest' started at 2020-01-09 17:15:59.243
Test Suite 'fatalTests' started at 2020-01-09 17:15:59.243
Test Case '-[fatalTests.fatalTests testExample]' started.
Fatal error: my string: file /private/tmp/fatal/Tests/fatalTests/fatalTests.swift, line 6
Exited with signal code 4
1 Like