sentry-native: Alternative backends on Windows don't catch crashes caused by `abort()`

Using Breakpad or inproc on Windows results in most crashes not being captured.

When does the problem happen

  • During build
  • During run-time
  • When capturing a hard crash

Environment

  • OS: Only Windows (in my case, Windows 10, 64-bit in VirtualBox)
  • Compiler: MSVC 19
  • CMake version and config: 3.21.2 -D SENTRY_BACKEND=breakpad -D BUILD_SHARED_LIBS=OFF

Steps To Reproduce

Just a simple boilerplate setup does it. Using abort() to cause the crash.

int main() {
  std::cout << "hello world" << std::endl;

  sentry_options_t* options = sentry_options_new();
  sentry_options_set_dsn(options, 'dsn redacted');
  sentry_options_set_debug(options, 1);

  sentry_init(options);

  std::this_thread::sleep_for(std::chrono::milliseconds(2000));

  abort();

  sentry_close();
}

Log output

This is the logs when it doesn’t work. As you can see, no crash is captured.

hello world
[sentry] INFO using database path "C:\Users\vagrant\NonRepos\SentryNativeTutorial\.sentry-native"
[sentry] DEBUG starting transport
[sentry] DEBUG starting background worker thread
[sentry] DEBUG starting backend
[sentry] DEBUG background worker thread started
The terminal process "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Command ./install/bin/tutorial.exe" terminated with exit code: 1.

However, if I swap out abort(); for

  volatile char* invalid_memory = nullptr;
  *invalid_memory = '\0';  // crash

to invoke a different kind of crash, I get

hello world
[sentry] INFO using database path "C:\Users\vagrant\NonRepos\SentryNativeTutorial\.sentry-native"
[sentry] DEBUG starting transport
[sentry] DEBUG starting background worker thread
[sentry] DEBUG starting backend
[sentry] DEBUG background worker thread started
[sentry] INFO entering breakpad minidump callback
[sentry] DEBUG merging scope into event
[sentry] DEBUG adding attachments to envelope
[sentry] DEBUG sending envelope
[sentry] DEBUG serializing envelope into buffer
[sentry] INFO crash has been captured
The terminal process "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Command ./install/bin/tutorial.exe" terminated with exit code: 1.

That is the first run, and on subsequent runs I see the envelope is uploaded and appears in the Sentry UI.

Similarly, if I change over to use crashpad as the backend, things work fine (but crashpad is not an option for me on this project). Things also work fine on Linux and Mac with the breakpad backend.

In my project, there’s a lot of assertions so most crashes are caused in the way that Windows can’t handle them.

For now, my hacky workaround is to register my own signal handler like so:

[[noreturn]] void windows_signal_handler(int signal) {
  volatile char* invalid_memory = nullptr;
  *invalid_memory = '\0';  // raising SEH exception EXCEPTION_ACCESS_VIOLATION_WRITE
  // unreachable
}
std::signal(SIGABRT, windows_signal_handler);

This results in the full stack trace appearing on the UI, albeit with an extra frame or two.

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Comments: 16 (4 by maintainers)

Most upvoted comments

Ah, this did in fact go away when I re-created a release build 🤦 looks like I’m back up and running! Apologies for the distraction @supervacuus and thanks for the help!

Makes sense, thanks. Let me circle back with @Swatinem which of these options would make most sense, and it could be multiple:

  • At very least, document limitations of secondary backends.
  • Patch a signal handler for std::abort into Breakpad’s win client in a minimal effort, double-checking past work. It’s actually surprising to me that it’s not there yet, but we’ll have to take a deeper look.
  • Same for the in-proc backend
  • Add a way to provide a transport function to crashpad_handler. This comes with the more general challenge of customizing the handler process which we haven’t tackled much, yet. I think the biggest challenge is around build tooling and a neat API for this.

Until then, you might have another workaround on your end. The SDK always vendors the getsentry branch of our Crashpad fork. The Windows HTTP transport, particularly ExecuteSynchronously is defined here. You could either provide your own implementation of the HttpTransport base class and swap that in, or patch out the Windows implementation to run gRPC internally. The file’s history seems fairly stable, which might make a custom patch feasible.

Many thanks. For now we’ll stick with Breakpad as we’ve got that implemented and working for the time being. We’ll bear the Crashpad patch solution in mind for the future though.