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

[Flutter Desktop Linux] sentry_init fails on fresh flutter app

Open jefflongo opened this issue 5 months ago • 7 comments

Platform

Flutter Desktop Linux

Obfuscation

Disabled

Debug Info

Disabled

Doctor

[✓] Flutter (Channel stable, 3.32.4, on Ubuntu 24.04.2 LTS 6.8.0-62-generic, locale en_US.UTF-8) [170ms]
    • Flutter version 3.32.4 on channel stable at ~/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 6fba2447e9 (12 days ago), 2025-06-12 19:03:56 -0700
    • Engine revision 8cd19e509d
    • Dart version 3.8.1
    • DevTools version 2.45.1

[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0) [1,183ms]
    • Android SDK at ~/Android/Sdk
    • Platform android-36, build-tools 35.0.0
    • Java binary at: /opt/android-studio/jbr/bin/java
      This is the JDK bundled with the latest Android Studio installation on this machine.
      To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
    • Java version OpenJDK Runtime Environment (build 21.0.5+-12932927-b750.29)
    • All Android licenses accepted.

[✗] Chrome - develop for the web (Cannot find Chrome executable at google-chrome) [106ms]
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[✓] Linux toolchain - develop for Linux desktop [334ms]
    • Ubuntu clang version 21.0.0 (++20250624083533+8d9911e4a06c-1~exp1~20250624083644.991)
    • cmake version 3.28.3
    • ninja version 1.11.1.git.kitware.jobserver-1
    • pkg-config version 1.8.1
    • OpenGL core renderer: NVIDIA GeForce RTX 3070/PCIe/SSE2 (X11)
    • OpenGL core version: 4.6.0 NVIDIA 550.144.03 (X11)
    • OpenGL core shading language version: 4.60 NVIDIA (X11)
    • OpenGL ES renderer: NVIDIA GeForce RTX 3070/PCIe/SSE2 (X11)
    • OpenGL ES version: OpenGL ES 3.2 NVIDIA 550.144.03 (X11)
    • OpenGL ES shading language version: OpenGL ES GLSL ES 3.20 (X11)
    • GL_EXT_framebuffer_blit: yes (X11)
    • GL_EXT_texture_format_BGRA8888: yes (X11)

[✓] Android Studio (version 2024.3) [104ms]
    • Android Studio at /opt/android-studio
    • Flutter plugin version 86.0.1
    • Dart plugin version 243.26753.1
    • android-studio-dir = /opt/android-studio
    • Java version OpenJDK Runtime Environment (build 21.0.5+-12932927-b750.29)

[✓] VS Code (version unknown) [15ms]
    • VS Code at /snap/code/current/usr/share/code
    • Flutter extension version 3.112.0
    ✗ Unable to determine VS Code version.

[✓] Connected device (1 available) [88ms]
    • Linux (desktop) • linux • linux-x64 • Ubuntu 24.04.2 LTS 6.8.0-62-generic

[✓] Network resources [226ms]
    • All expected network resources are available.

Version

9.1.0

Steps to Reproduce

Create app from template:

flutter create -t app my-app
cd my-app
flutter pub add sentry_flutter

Modify main.dart:

Future<void> main() async {
  await SentryFlutter.init((options) {
    options.dsn = 'some-dsn'; // insert dsn here
    options.diagnosticLevel = SentryLevel.debug;
  }, appRunner: () => runApp(const MyApp()));
}

Build and run:

flutter build linux
flutter run

Expected Result

Sentry builds and launches successfully.

Actual Result

Several warnings while compiling flutter build linux, still builds though.

~/Downloads/my-app/build/linux/x64/release/_deps/sentry-native-src/external/crashpad/util/linux/thread_info.cc:22:10: warning: first argument in call to 'memset' is a pointer to non-trivially copyable type 'crashpad::ThreadContext' [-Wnontrivial-memcall]
~/Downloads/my-app/build/linux/x64/release/_deps/sentry-native-src/external/crashpad/util/linux/thread_info.cc:28:10: warning: first argument in call to 'memset' is a pointer to non-trivially copyable type 'crashpad::FloatContext' [-Wnontrivial-memcall]
/usr/bin/ld: warning: crashpad_info_note.S.o: missing .note.GNU-stack section implies executable stack
/usr/bin/ld: warning: crashpad_info_note.S.o: missing .note.GNU-stack section implies executable stack

Log messages indicating that sentry_init failed due to invalid handler_path

(com.example.fluttertest:76207): Atk-CRITICAL **: 13:58:20.973: atk_socket_embed: assertion 'plug_id != NULL' failed
[sentry] INFO using database path "~/Downloads/my-app/.sentry-native"
[sentry] DEBUG starting transport
[sentry] DEBUG starting background worker thread
[sentry] DEBUG starting backend
[sentry] DEBUG background worker thread started
[sentry] WARN unable to start crashpad backend, invalid handler_path
[sentry] WARN failed to initialize backend
[sentry] WARN `sentry_init` failed
[sentry] DEBUG shutting down transport
[sentry] DEBUG shutting down background worker thread
[sentry] DEBUG submitting task to background worker thread
[sentry] DEBUG executing task on worker thread
[sentry] DEBUG background worker thread shut down

Are you willing to submit a PR?

No

jefflongo avatar Jun 24 '25 21:06 jefflongo

hey, it seems our native crash handler is failing to set up. It does not affect the rest of the SDK but we'll have a look.

You can disable it by setting the SENTRY_NATIVE_BACKEND env var to none or try setting it to breakpad instead.

buenaflor avatar Jun 24 '25 21:06 buenaflor

@jefflongo would you mind checking what the value of crashpadPath is in this line when you init Sentry https://github.com/getsentry/sentry-dart/blob/e788bd4a93003174ff6134df5ac6dd50c3d8e09a/flutter/lib/src/native/c/sentry_native.dart#L80

buenaflor avatar Jun 24 '25 21:06 buenaflor

@buenaflor I've tracked down the cause of this problem. There are two issues:

First, this code checks the app dir for the crashpad handler. For me, it resided in appDir/lib. sentry-dart/flutter/lib/src/native/c/sentry_native.dart

So adding this line allowed it to find the crashpad handler. '$appDir${Platform.pathSeparator}lib/crashpad_handler'

Second, the native init fails because the crashpad handler does not have execute permissions. If I chmod +x the crashpad handler everything works. However, the crashpad handler seems to get regenerated without execute permissions every time I build the app.

jefflongo avatar Jun 25 '25 01:06 jefflongo

thanks for the in-depth research. I'll add $appDir${Platform.pathSeparator}lib/crashpad_handler to the candidates paths.

as for the permissions: @JoshuaMoelans do you know more about how to handle this? is this generally an issue in sentry-native?

buenaflor avatar Jun 25 '25 09:06 buenaflor

cc @vaind maybe you have an idea

buenaflor avatar Jun 25 '25 11:06 buenaflor

Flutter's SDK sentry-native integration just uses upstream CMake to build things. @supervacuus WDYT? maybe we could/should add POST_BUILD step with chmod +x to crashpad?

vaind avatar Jun 25 '25 11:06 vaind

I'm wondering if the problem has to do with crashpad_handler ending up in the lib folder. Guessing here without much understanding of how Flutter installs crashpad_handler, but maybe Flutter copies files into lib in such a way where permissions are not maintained. If this is the case, chmod +x in a POST_BUILD step would not help. Seems like getting crashpad_handler to end up in bin would be more likely to maintain the execute permission, given that it's a bin folder.

jefflongo avatar Jun 26 '25 04:06 jefflongo

I think @jefflongo is right. This is not a build issue. Any toolchain should create executable binaries; doing it in the CMake build script is either too soon (because the toolchain set the executable bit correctly already, but then something else post-build or post-install modifies it) or too late (the toolchain couldn't set the executable bit, which was probably due to some filesystem restrictions, in which case the POST_BUILD step won't fix it either).

@jefflongo, could you have a look at the intermediate build output path:

<your_app>/build/linux/x64/release/_deps/sentry-native-build/crashpad_build/handler

whether the executable permission bit of the crashpad_handler is set?

supervacuus avatar Jun 26 '25 10:06 supervacuus

I think @jefflongo is right. This is not a CMake issue. Any toolchain should create executable binaries; doing it in the CMake build script is either too soon (because the toolchain set the executable bit correctly already, but then something else post-build or post-install modifies it) or too late (the toolchain couldn't set the executable bit, which was probably due to some filesystem restrictions, in which case the POST_BUILD step won't fix it either).

@jefflongo, could you have a look at the intermediate build output path:

<your_app>/build/linux/x64/release/_deps/sentry-native-build/crashpad_build/handler

whether the executable permission bit of the crashpad_handler is set?

The intermediate build has permissions 0775 (execute bit is set), the output build has permissions 0644 (execute bit is not set). This confirms that Flutter is copying the file over in a way that strips the execute permission.

jefflongo avatar Jun 26 '25 14:06 jefflongo

  • sentry-dart/flutter/sentry-native/sentry-native.cmake (which is used by ../linux/CmakeLists.txt) appends the crashpad handler executable to sentry_flutter_bundled_libraries list
  • this list is appended to PLUGIN_BUNDLED_LIBRARIES by the flutter-generated <your-app>/linux/flutter/generated_plugins.cmake
  • PLUGIN_BUNDLED_LIBRARIES is set up with install() cmake command in <your-app>/linux/CMakeLists.txt as follows (by default when first generated by new flutter app template, however, you may have edited it manually):
      install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
      DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
      COMPONENT Runtime)
    
  • I believe the former is the culprit. Although I have worked a quite a bit with cmake, somehow I've had basically zero experience with install() configuration. However, from what I could find online, it's possible install strips permissions. There seem to be settings to preserve (or explicitly configure) permissions, see cmake docs, but I'm unfamiliar with them to know for sure.

vaind avatar Jun 26 '25 18:06 vaind

However, from what I could find online, it's possible install strips permissions.

Yes, that is very true, and install(FILES ...) is the core of the problem.

Binaries (and executables specifically) should be installed using install(TARGETS ...) or, in cases like this one, where the targets are not part of the install project and you still want to maintain executable bits, with install(PROGRAMS ...).

Can't say how well this integrates, but maybe a second variable PLUGIN_BUNDLED_EXECUTABLES (or *_PROGRAMS) is the right choice here, then you won't have to handle permissions in the install path explicitly.

This proposal by a Flutter developer is close to what I have in mind if one wanted to fix this upstream.

supervacuus avatar Jun 26 '25 21:06 supervacuus

I'm not really knowledgable in cmake, does that mean we have a potential way to work around this without fixing it upstream?

is this something you can take care of? @vaind

if you're busy I can also take a look

buenaflor avatar Jun 30 '25 07:06 buenaflor

I'm not really knowledgable in cmake, does that mean we have a potential way to work around this without fixing it upstream?

While Flutter's usage of CMake install() is at the core of this issue, it boils down to the options you have inside the Flutter build environment (of which I have not enough insight).

I was able to verify that special-casing the crashpad_handler by patching <your-app>/linux/CMakeLists.txt with the following fixes the problem:

foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
  if("${bundled_library}" STREQUAL "$<TARGET_FILE:crashpad_handler>")
    install(PROGRAMS "${bundled_library}"
      DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
      COMPONENT Runtime)
  else()
    install(FILES "${bundled_library}"
      DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
      COMPONENT Runtime)
  endif()
endforeach()

Of course, this requires your users to modify the auto-generated build script, which is not great. When I speak of upstreaming, I mean that Flutter could provide additional lists (such as PLUGIN_BUNDLED_TARGETS and PLUGIN_BUNDLED_PROGRAMS) as an interface to this auto-generated build script, which would use the respective install command, thereby eliminating the need for special casing. I have no idea if there are better hooks available to either fix up the permissions after bundle installation or modify the build script automatically.

supervacuus avatar Jun 30 '25 15:06 supervacuus

In that case one option for now could be to document this properly and have users patch their CMakeLists.txt

and additionally we could let our wizard patch it as well

buenaflor avatar Jul 01 '25 14:07 buenaflor

Updated the docs for patching the user's cmakelists and the additional path to look for the crashpad handler has been added in 9.4.0

buenaflor avatar Jul 10 '25 22:07 buenaflor

I'll add the link here in case people come directly to this issue from google: https://docs.sentry.io/platforms/dart/guides/flutter/troubleshooting/#issues-with-native-crashes-on-linux-andor-windows

spydon avatar Aug 19 '25 14:08 spydon