crash can not be captured on windows
I am using flutter to develop app. and use sentry to capture crash. C PlusPlus code is called by ffi which is manged by dart in flutter. Now, The crash is not captured in c plusplus code, try to use crashpad/breakpad/inproc backend, fail to capture the crash. Found The issue which is in the dart website. https://github.com/dart-lang/sdk/issues/39140 FFI is only a C-based. Maybe c plus plus exceptions can not be captured. Is that why Crash can not be captured by sentry ? If i want to capture the crash, which methods can be used ?
- OS: [e.g. Windows 10, 64-bit]
- Compiler: [e.g. MSVC 22]
- CMake version and config: [e.g. 3.17.2, SENTRY_BACKEND=inproc]
Hi @chenxinhua2021! I need more context because I am not well-versed in Flutter. Especially the following questions immediately pop up in my head:
- do you only initialize the Native SDK in a C++ FFI module?
- (or) are you using the Dart SDK for your flutter application too?
- how do you initialize the Native SDK? does the FFI library keep a global sentry context?
- does the initialization work for you (would you see any error when you enable the debug output)?
- can you send normal events successfully?
What I can tell you:
- There is an open ticket to integrate the Native SDK into the Dart SDK to support Flutter Desktop applications on Windows: https://github.com/getsentry/sentry-dart/issues/896. This means there is currently no support for native crashes on Windows in the Dart SDK.
- The Native SDK doesn't handle C++ exceptions on a language level (i.e., we do not hook into
std::terminate), but every uncaught C++ exception will lead to a low-level exception which we will capture. - The issue you linked to talks about safely handling exceptions through the FFI boundary. This is only partially related: you must provide a C wrapper to your C++ code when using the Dart FFI to guarantee defined behavior in an error case. If the VM crashes due to letting a C++ exception escape through the FFI boundary, then our crash handler should be able to capture this too. But:
- It is entirely unclear to me how Dart handles (SEH) exceptions on Windows and how FFI modules might be sandboxed in a way that will prevent the useful operation of unhandled exception filters (which our backends would need to function correctly). A core task of https://github.com/getsentry/sentry-dart/issues/896 is figuring out how (and if) Dart allows FFI code to set this up correctly.
Thank you very much for your fast reply @supervacuus . I use dart sdk and native sdk in my flutter application.
Native sdk Initialize:
sentry_options_t* options = sentry_options_new();
sentry_options_set_dsn(options, "https://
When you say "other crashes can be captured", do you mean dart crashes or other native crashes (like an access violation) from an FFI module? I guess any other SEH exception from an FFI module would also not be reported. I cannot tell you when I will have time to investigate this further, but it is on our agenda.
Yes, any other SEH exception from an FFI module is not reported. Other crashes Which is maked by c++ plugin to be called by flutter can be captured. I will try to do a simple demo to present the problem.
Ok, thanks for verifying. So the C++ FFI aspect seems to be a red herring in this issue since C++ exceptions on Windows are just SEH exceptions.
If SEH exceptions fail to report, the problem lies with the registration or the execution environment of the unhandled exception filter in our backend because Dart installs one itself during the startup of the runtime.
This filter would normally print a stack trace if there was a native crash. The Native SDK in turn would overwrite that filter with its backend-specific implementation. Can you compare whether crashing from the FFI module prints a stack trace without initializing the Native SDK?
I try to use windows system api (SetUnhandledExceptionFilter), crash can not be captured which is maked c++ code which is called FFI module.
Stack information can be printed in visual studio tool when crash from ffi module.
Hi @supervacuus we make a simple demo to present the problem. this is url. https://github.com/Arctuition/dart-ffi-crash There are two ways to verify crash. Same program call ffi interface and c++ plugin. Crash in Ffi module( c++ code be called) can not be captured. Crash in c++ plugins can be captured.
Thank you for preparing a repro that covers the FFI and plugin case, @chenxinhua2021. As I said before, I cannot say when I will have the time to dive into this.
@marandaneto, I think you will be involved in the dart/native evaluation, right? @chenxinhua2021 prepared a repro-repo, that fails at capturing SEH from FFI modules but is successful when crashing in Flutter plugins. Even if this is not actionable for you rn, I think the Dart-SDK team should be aware of this issue. I will try to figure out where in the FFI boundary the exception propagation fails and if we can even do something about it from the Native SDK.
Thank you very much for your reply @supervacuus . I have consulted on drak sdk, some reply may be is worthy for you.
Thank you for preparing a repro that covers the FFI and plugin case, @chenxinhua2021. As I said before, I cannot say when I will have the time to dive into this.
@marandaneto, I think you will be involved in the dart/native evaluation, right? @chenxinhua2021 prepared a repro-repo, that fails at capturing SEH from FFI modules but is successful when crashing in Flutter plugins. Even if this is not actionable for you rn, I think the Dart-SDK team should be aware of this issue. I will try to figure out where in the FFI boundary the exception propagation fails and if we can even do something about it from the Native SDK.
That's correct, it's not a supported use case yet, and apparently, there's a dependency with https://github.com/dart-lang/sdk/issues/51726#issuecomment-1476465547 and its exception filters. If @chenxinhua2021 is setting up sentry-native directly in the Flutter app, that should work, that's exactly what we'd do when tackling https://github.com/getsentry/sentry-dart/issues/896 (but automatically) so if there's a problem, we'd need to consider that as well.
Hi @marandaneto, yes, that is why I hooked you in. You will experience the same issue with any native code called from Dart-generated code (it happens with JIT and AOT). As mentioned here, it is not specific to FFI modules (though it will mostly be an issue there) but related to unwinding the Dart code regions in case of a crash on Windows.
@chenxinhua2021 did you manage to make this work in the end? I see that dart team fixed the underlying issue.
+1 this would be great
ty to Sentry team
To be clear, @isaacy13: the issue had to be fixed in Dart itself and not in Sentry's SDKs. The fix was released with Dart 3.0.0-422.0.dev. The implementation for Windows ARM64 still needs to be completed.
We only keep this issue open as a test target to consider for Windows Desktop support in the Dart SDK. As far as we know, there is nothing to do on the side of the Native SDK to allow crash reporting for Windows native code as long as you deploy to a Dart environment with the above fix.
cc @kahest
Ah perfect, thank you @supervacuus for the clarification
Perhaps this belongs in another ticket (not sure if Dart or Sentry), but whenever FFI C++ code is calling abort(), I'm not seeing logs in Sentry
Sometimes I don't even get the abort() message -- it just crashes, but a little debugging shows the various exceptions that are thrown to crash the program (null access, division by 0, etc.)
For context: https://github.com/media-kit/media-kit/issues/743
- Flutter 3.19.3
- Dart 3.3.1
- Windows 11 x64
I've previously done Sentry quick setup & verified logs do show up when following these steps https://docs.sentry.io/platforms/flutter/#verify
Also, Sentry is initialized before the exceptions are thrown
@isaacy13 I'm seeing the same behavior (i.e. no information in sentry dashboard on C++ crashes), but from what I understand this is expected behavior.
You would need to integrate the Sentry Native like @chenxinhua2021 in this example if you want to have that work.
I wanted to try this myself but I'm afraid I don't have the time right now, even if it looks like most of the work has been done in that example. Let me know if you try it.
p.s. don't expect native crashes to be reported instantaneously like other flutter exceptions, they only show up after you reopen the app after the crash
@alexvoina Thanks for the info
After re-reading with a fresher pair of eyes, my understanding has changed
As @supervacuus said previously, the Dart team fixed the issue from @chenxinhua2021's post (https://github.com/dart-lang/sdk/issues/51726)
- so the FFI vs. plugin difference referenced in here turned out to be a symptom of another issue related to stack unwinding
I poked around a bit and the problem is indeed not related to FFI, but rather to the failure to unwind the stack. https://github.com/dart-lang/sdk/issues/51726#issuecomment-1476465547
Ok, thanks for verifying. So the C++ FFI aspect seems to be a red herring in this issue since C++ exceptions on Windows are just SEH exceptions. https://github.com/getsentry/sentry-native/issues/818#issuecomment-1469911175
I suspect the thing I'm missing is initializing Sentry in C++ -- I am currently only initializing Sentry in Flutter
Thank you very much for your fast reply @supervacuus . I use dart sdk and native sdk in my flutter application. Native sdk Initialize: sentry_options_t* options = sentry_options_new(); sentry_options_set_dsn(options, "https://@sentry.io/"); sentry_init(options); https://github.com/getsentry/sentry-native/issues/818#issuecomment-1468030807
But with my current understanding of the various threads, it sounds like things should be working, just need to give it another shot -- I expect to report back to this thread this weekend or the next with results
I suspect the thing I'm missing is initializing Sentry in C++ -- I am currently only initializing Sentry in Flutter
Yes, that's right. The Native SDK and the Dart SDK are not yet integrated for Flutter on Windows (https://github.com/getsentry/sentry-dart/issues/896).
The Native SDK can detect any unhandled crash outside the managed environment, while the Dart SDK will report errors from within Dart/Flutter, such as exceptions or failed assertions.
The latter will be enough for most Flutter Applications, but when using native libraries via Dart's FFI or as Flutter plugins, you might need a native crash handler. For most supported platforms of the Dart SDK, these native crash handlers are already integrated (for instance, on Android, you will get NDK crashes reported via sentry-android, which uses the Native SDK under the hood).
But with my current understanding of the various threads, it sounds like things should be working, just need to give it another shot
There is currently no indication that the Native SDK and the Dart SDK can't operate next to each other (they won't cooperate, you will have to initialize them separately, and scope changes will not be synced).
@isaacy13 really looking forward to hearing your report
@alexvoina
A lot later than I expected to be replying -- but everything is working as expected
Steps taken on Windows:
- follow setup steps for Sentry Native (download and build with crashpad_handler)
- add includes/libs/dlls in
windows/runner/CMakeLists.txt - make sure
crashpad_handler.exeis inwindows/runnerfolder #include "sentry_init.h"inwindows/runner/main.cpp
Now, whenever I throw an exception in plugin libraries' C++ code, I get the alert in Sentry!
notes:
- separate Sentry-native project must be created (cannot use DSN from Sentry-flutter)
- can use sentry-cli to upload debug symbol files (e.g.: upload files each time running project or running project thru pipeline)
- TODO: need to test multiple threads in C++
windows/runner/CMakeLists.txt
...
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}" path_to_sentry_include_folder)
target_link_libraries(${BINARY_NAME} PRIVATE path_to_sentry_lib_file)
add_custom_command(TARGET ${BINARY_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
path_to_sentry_dll_file
$<TARGET_FILE_DIR:${BINARY_NAME}>)
...
sentry_init.h
#ifndef SENTRY_INIT_H
#define SENTRY_INIT_H
#include "sentry.h"
class SentryInit {
public:
SentryInit() {
sentry_options_t *options = sentry_options_new();
sentry_options_set_dsn(options, your_dsn_here);
sentry_options_set_handler_path(options, path_to_crashpad);
sentry_options_set_database_path(options, path_to_db_path);
sentry_options_set_release(options, "[email protected]");
sentry_options_set_debug(options, 1);
sentry_init(options);
}
~SentryInit() {
sentry_close();
}
};
static SentryInit sentryInit;
#endif // SENTRY_INIT_H
@isaacy13 it is never too late! Can't wait to try this myself too <3 Big thanks for all the explanations & code
closing this now as resolved. related PR for sentry-native integration: https://github.com/getsentry/sentry-dart/pull/2286