sentry-native icon indicating copy to clipboard operation
sentry-native copied to clipboard

crash can not be captured on windows

Open chenxinhua2021 opened this issue 2 years ago • 21 comments

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]

chenxinhua2021 avatar Mar 14 '23 06:03 chenxinhua2021

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.

supervacuus avatar Mar 14 '23 09:03 supervacuus

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); I can get dump file in the path of my project by making some crashes which is not in ffi module. In addition, normal events can be successfully sent. and other crashes can be captured, only the crash that c++ is called by ffi module can not be captured.

chenxinhua2021 avatar Mar 14 '23 12:03 chenxinhua2021

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.

supervacuus avatar Mar 15 '23 10:03 supervacuus

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.

chenxinhua2021 avatar Mar 15 '23 11:03 chenxinhua2021

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?

supervacuus avatar Mar 15 '23 12:03 supervacuus

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.

chenxinhua2021 avatar Mar 16 '23 01:03 chenxinhua2021

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.

chenxinhua2021 avatar Mar 16 '23 11:03 chenxinhua2021

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.

supervacuus avatar Mar 21 '23 08:03 supervacuus

Thank you very much for your reply @supervacuus . I have consulted on drak sdk, some reply may be is worthy for you.

chenxinhua2021 avatar Mar 21 '23 08:03 chenxinhua2021

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.

marandaneto avatar Mar 21 '23 09:03 marandaneto

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.

supervacuus avatar Mar 21 '23 10:03 supervacuus

@chenxinhua2021 did you manage to make this work in the end? I see that dart team fixed the underlying issue.

alexvoina avatar Mar 27 '24 15:03 alexvoina

+1 this would be great

ty to Sentry team

isaacy13 avatar Mar 30 '24 22:03 isaacy13

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

supervacuus avatar Mar 31 '24 14:03 supervacuus

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 avatar Mar 31 '24 20:03 isaacy13

@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 avatar Apr 01 '24 06:04 alexvoina

@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

isaacy13 avatar Apr 02 '24 03:04 isaacy13

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).

supervacuus avatar Apr 02 '24 09:04 supervacuus

@isaacy13 really looking forward to hearing your report

alexvoina avatar Apr 02 '24 12:04 alexvoina

@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.exe is in windows/runner folder
  • #include "sentry_init.h" in windows/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 avatar May 15 '24 02:05 isaacy13

@isaacy13 it is never too late! Can't wait to try this myself too <3 Big thanks for all the explanations & code

alexvoina avatar May 15 '24 06:05 alexvoina

closing this now as resolved. related PR for sentry-native integration: https://github.com/getsentry/sentry-dart/pull/2286

kahest avatar Dec 12 '24 15:12 kahest