Trying to get crash backtracing to work on Windows

I am trying to get the Swift runtime's crash backtracing to work for my Swift (Windows App SDK) GUI app (as a starting point for building some crash reporting service around that later on).

I am using a very recent Swift 6.4 Windows toolchain on an Intel machine running Windows 11. My build setup is CMake-based, not SPM-based.

I have read the Backtracing support in Swift documentation, and using the following configuration

set SWIFT_BACKTRACE=interactive=no,output-to=C:\tmp\CrashLogs

I also tried including more flags, like swift-backtrace=C:\Swift\Runtimes\6.4.0\usr\libexec\swift\swift-backtrace.exe, or symbolicate=off, also with quotes around the paths, but none of that made a difference.

To simulate a crash, I am calling fatalError() in my app, I hope that's sufficient; it certainly does crash the app, and Windows Error Reporting kicks in (see below), so I suppose it is.

The behaviour I am seing is that no crash logs are written to the folder specified in the environment variable. I first tried a relwithdebinfo build and later also a debug build, with the same outcome.

Note that my app doesn't have a console window / stdout; I am specifying

target_link_options(Compositor PRIVATE
    -Xlinker /SUBSYSTEM:WINDOWS
)

to make this a GUI app (with winMain entry point instead of main) that launches without opening a terminal window (which would be unacceptable for my use case).

After getting no crash logs, I recorded a short app session using Windows Performance Recorder to see what happens around crash time. Windows Error Reporting (WerFault.exe, wermgr.exe) seem to kick in when the crash happens:

And here's what I assume are corresponding logs in the Windows Event Viewer:

But I don't know if that's helpful for diagnosing Swift backtracing.

I will be in tomorrow's Windows Workgroup meeting anyway, but I wanted to write this up beforehand and hopefully give useful information for further diagnosis.

thanks,
Karl

Edit: swift-backtrace.exe does not show up in the list of processes around the crash time; it looks like the runtime wasn't able to launch it (I understand it runs as a process external to the crashing app):

I'm sorry to hear it @ktraunmueller ... we chatted a bit on the Windows Office Hours call so I'm repeating a bit for anyone else who is reading this post or interested in the native swift runtime crash logging/backtracing on Windows.

I think the top line thing I'd say is generally it should (and mostly does!) work on straight out of the box installations. It certainly has for me. So I don't think you're doing anything wrong.

When I get a chance I'll try installing the latest Swift 6.4 toolchain and just check that it seems to be fine. We have a fairly extensive suite of Backtracer tests that run on Windows CI machines that you can see on the usual swift.org CI pages.

If you can post your project source code or (much better) a minimum reproducer of the issue on here that would help, as I can try to reproduce the issue on my Windows 11 PC with the latest swift 6.4 Windows installer package.

If you look at this example unit test from the swift repository:

You can see a sort of classic simple program that you can build using the swift on windows toolchain and when you run it you should see a nice crash log on the console. If that doesn't work then something is odd on your installation.

If you're able to get Windows crash logs from "normal"/simple swift programs built using the toolchain from the swift 6.4 installer on your Windows PC, then I guess it's something specific about your project, and we'll have to dig into the source code.

I hope this helps as a first few steps. I'm very keen to help get you up and running if we can.

Carl

p.s. Unfortunately I have to go on annual leave for the rest of this week, however don't let that stop you from replying. Quite likely other readers of the forums can chip in with help if you post a reply. Good luck!

p.p.s. [edit] One final note, if you do get a backtrace from a test program or your own program but it is not symbolicated, you might need to make sure that debug symbols are being emitted in your build. See the documentation in swift/docs/Backtracing.rst at main · swiftlang/swift · GitHub and the forum post detailing the backtracer written when it was launched: On-Crash Backtraces in Swift | Swift.org for more help on that or, as always, ask for help on here!

1 Like

Thanks Carl @carlpeto

Using this little test program

func kablam() {
  kerpow()
}

func kerpow() {
  whap()
}

func whap() {
  zonk()
}

func zonk() {
  splat()
}

func splat() {
  pow()
}

func pow() {
  fatalError("Kablam!")
}

@main
struct SymbolicatedBacktrace {
  static func main() {
    kablam()
  }
}

and compiling and running it on my (Intel) machine

C:\tmp>%SWIFT_TOOLCHAIN_PATH%\bin\swiftc -O -g -debug-info-format=codeview -Xlinker /DEBUG -parse-as-library crasher.swift -o crasher.exe
   Creating library crasher.lib and object crasher.exp

C:\tmp>crasher.exe
crasher/crasher.swift:22: Fatal error: Kablam!

đź’Ł Program crashed: Illegal instruction at 0x00007ff95644be7e

Platform: x86_64 Windows 11.0 build 26200

Thread 0 crashed:

0 0x00007ff95644be7e <unknown> in swiftCore.dll
1 0x00007ff6006b182d main + 92 in crasher.exe
2 0x00007ff9a43fccb7 <unknown> in KERNEL32.DLL
3 0x00007ff9a608ad6c <unknown> in ntdll.dll

Backtrace took 0.04s

I am getting a backtrace on the console, so that's looking good.

As suggested in the last Windows workgroup meeting by @al45tair, I recorded a (simulated) crash in my installed app with procmon - the log is available here, if that's of any help (the process is Compositor.exe, a RelWithDebInfo x86_64 build).

Thanks,
Karl

It looks like it's looking for swift-backtrace.exe in C:\Program Files\WindowsApps\Compositor_0.8.2.0_x64__b202aj40gcyaw\swift-backtrace.exe (i.e. alongside your program). I don't understand why it is ignoring the content of the SWIFT_BACKTRACE environment variable, mind — you'd specified that it should be in a different location to that.

Ah, I forgot (in my installer script) that I will need to bundle swift-backtrace.exe alongside the other Swift runtime libraries anyway:

# Copy binaries
Copy-Item -Path "$buildOutputFolder\Compositor.exe" -Destination "$installerStagingFolder" -Force

# Copy supplementary Windows App SDK binaries
Copy-Item -Path "$buildOutputFolder\swift-windowsappsdk_CWinAppSDK.resources" -Destination "$installerStagingFolder" -Recurse -ErrorAction SilentlyContinue
Copy-Item -Path "$buildOutputFolder\Microsoft.Graphics.Canvas.dll" -Destination "$installerStagingFolder" -Force -Recurse -ErrorAction SilentlyContinue

# Copy Swift binaries
Copy-Item -Path "$swiftRuntimeFolder\bin\swiftCRT.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\swiftCore.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\swiftDispatch.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\swiftWinSDK.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\swift_Concurrency.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\swift_RegexParser.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\swift_StringProcessing.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\swiftObservation.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\swiftSynchronization.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\BlocksRuntime.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\dispatch.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\Foundation.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\FoundationEssentials.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\FoundationInternationalization.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\FoundationNetworking.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\bin\_FoundationICU.dll" -Destination "$installerStagingFolder" -Force
Copy-Item -Path "$swiftRuntimeFolder\libexec\swift\swift-backtrace.exe" -Destination "$installerStagingFolder" -Force  # <-- this had been missing

Then I can remove the path argument from the SWIFT_BACKTRACE environment variable again:
enable=yes,interactive=no,symbolicate=off,output-to=C:\tmp\CrashLogs

But still nothing in C:\tmp\CrashLogs after a simulated crash.
Here's another log with the backtracer now in the app installation folder.

OK, I don't see anything especially obvious in that log, though I do note that we aren't trying to create the swift-backtrace.exe process, which suggests that something has altered the Windows exception handling set-up (which is how we trap errors).

1 Like

Complete tangent: use of the MSM would allow you to ignore the "Copy Swift binaries" segment - including swift-backtrace.exe.

Yeah, I really need to change the runtime distribution setup.