Repository navigation
Conversation
7ea304b to
11f94c3
Compare
| if (sentry__atomic_fetch(&g_preloaded)) { | ||
| g_crash_ipc = NULL; | ||
| SENTRY_DEBUG("crash handler deactivated, keeping preloaded handlers"); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Bug: The signal stack (g_signal_stack.ss_sp) allocated during preload is never freed on shutdown, causing a memory leak.
Severity: MEDIUM
Suggested Fix
The shutdown logic for the preloaded case should be updated to free the resources it allocated. Specifically, the memory for g_signal_stack.ss_sp should be freed and the signal stack should be disabled before the function returns, even when g_preloaded is true.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: src/backends/native/sentry_crash_handler.c#L920-L924
Potential issue: When the crash handler is preloaded by calling
`sentry__crash_handler_preload()`, memory is allocated for a signal stack and assigned
to `g_signal_stack.ss_sp`. However, during shutdown
(`sentry__crash_handler_shutdown()`), an early return is taken if the `g_preloaded` flag
is set. This bypasses the cleanup logic that frees the allocated signal stack. As a
result, the memory for `g_signal_stack.ss_sp` is never deallocated, leading to a memory
leak in applications that use the preload feature and then shut down the handler.
| char *serialized = sentry_envelope_serialize(envelope, &size_out); | ||
| printf("%s", serialized); |
There was a problem hiding this comment.
Bug: The return value of sentry_envelope_serialize is not checked for NULL before being passed to printf, which can cause a crash in out-of-memory situations.
Severity: LOW
Suggested Fix
Add a null-check for the serialized variable after calling sentry_envelope_serialize. If the variable is NULL, handle the error gracefully, for example by skipping the printf call, to prevent a crash.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: src/transports/sentry_transport_stdout.c#L11-L12
Potential issue: Under extreme out-of-memory conditions, the function
`sentry_envelope_serialize` can return a `NULL` pointer. This occurs if an internal
1-byte memory allocation for an empty string fails. The code passes this `NULL` return
value directly to `printf` without a check. This results in undefined behavior and is
known to cause a segmentation fault and crash on platforms like Android using the Bionic
libc.
| fail: | ||
| if (ipc->init_mutex) { | ||
| sentry__mutex_unlock(ipc->init_mutex); | ||
| } | ||
| if (ipc->shmem) { | ||
| munmap(ipc->shmem, SENTRY_CRASH_SHM_SIZE); | ||
| } | ||
| if (ipc->notify_fd >= 0) { |
There was a problem hiding this comment.
Bug: The native initialization function closes caller-provided file descriptors on failure without notifying the caller, leading to stale file descriptors on the Java side.
Severity: HIGH
Suggested Fix
The callee (sentry__crash_ipc_init_app_with_fds) should not close file descriptors that it does not own. The function should instead return an error code to the caller, sentry_android_crash_daemon_init, which can then propagate the failure status back to the Java layer. The caller, which owns the file descriptors, should be responsible for closing them upon learning of the initialization failure.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: src/backends/native/sentry_crash_ipc.c#L117-L124
Potential issue: During native crash daemon initialization via `nativeInitCrashDaemon`,
file descriptors (`notify_fd`, `ready_fd`) are passed from Java to the native layer. If
an error occurs during the subsequent initialization in
`sentry__crash_ipc_init_app_with_fds` (e.g., an `mmap()` failure), the error handling
logic closes these file descriptors. However, the original caller on the Java side is
not notified of this failure or that the descriptors have been closed. This leaves the
caller with stale file descriptors, which can lead to data corruption or crashes if they
are used later, as they might have been recycled by the OS for other resources.
6460208 to
527d4dc
Compare
c451ff8 to
5a7389f
Compare
The lint failure in #1725 is reproducible locally with `make -C ndk check`, even on `master`. CI on `master` happens to pass because it reuses cached `lintAnalyzeDebug` results. Fresh analysis reports dependency update notices that `warningsAsErrors` makes fatal: ```text > Task :sentry-native-ndk:lintDebug FAILED ndk/gradle/wrapper/gradle-wrapper.properties:3: Error: A newer version of Gradle than 9.7.1 is available: 9.8.0 [AndroidGradlePluginVersion] ndk/lib/build.gradle.kts:134: Error: A newer version of org.jetbrains:annotations than 23.0.0 is available: 24.0.1 [GradleDependency] ``` Disable these checks alongside `NewerVersionAvailable`. Always rerun lint analysis so CI cannot reuse a passing result when dependency metadata changes.
The lint failure in #1725 is reproducible locally with `make -C ndk check`, even on `master`. CI on `master` happens to pass because it reuses cached `lintAnalyzeDebug` results. Fresh analysis reports dependency update notices that `warningsAsErrors` makes fatal: ```text > Task :sentry-native-ndk:lintDebug FAILED ndk/gradle/wrapper/gradle-wrapper.properties:3: Error: A newer version of Gradle than 9.7.1 is available: 9.8.0 [AndroidGradlePluginVersion] ndk/lib/build.gradle.kts:134: Error: A newer version of org.jetbrains:annotations than 23.0.0 is available: 24.0.1 [GradleDependency] ``` Disable these checks alongside `NewerVersionAvailable`. Always rerun lint analysis so CI cannot reuse a passing result when dependency metadata changes.
5a7389f to
b93f5ad
Compare
| ipc->shmem = NULL; | ||
| close(ipc->shm_fd); | ||
| sentry_free(ipc); | ||
| return NULL; | ||
| } | ||
|
|
||
| if (ipc->shmem->magic != SENTRY_CRASH_MAGIC) { | ||
| SENTRY_WARN("daemon: invalid shared memory magic"); | ||
| munmap(ipc->shmem, SENTRY_CRASH_SHM_SIZE); | ||
| close(ipc->shm_fd); | ||
| sentry_free(ipc); |
There was a problem hiding this comment.
Bug: The Android crash daemon leaks file descriptors if sentry__crash_ipc_init_daemon fails during initialization, as the cleanup path is skipped.
Severity: HIGH
Suggested Fix
Modify sentry__crash_ipc_init_daemon to close the notify_eventfd and ready_eventfd file descriptors in all early-return failure paths, such as after a failed mmap call or an invalid magic number check. This ensures that the file descriptors are always cleaned up, even if the IPC initialization does not complete.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: src/backends/native/sentry_crash_ipc.c#L182-L192
Potential issue: In the Android crash handler, the `sentry__crash_ipc_init_daemon`
function can leak file descriptors. If `mmap` fails, the magic number in shared memory
is invalid, or the initial memory allocation for the `ipc` struct fails, the function
returns `NULL` without closing the `notify_eventfd` and `ready_eventfd` file
descriptors. The caller's cleanup logic in `android_cleanup_pending_crash_daemon` only
frees these resources if the `ipc` struct was successfully initialized, which it is not
in these failure cases. This results in a resource leak that could exhaust the process's
file descriptor limit after multiple crashes, preventing future crash handling.
Also affects:
src/backends/native/sentry_crash_ipc.c:175~178
|
|
||
| // On Linux, allow the daemon to ptrace this process | ||
| // This is required when Yama LSM ptrace_scope is enabled | ||
| if (prctl(PR_SET_PTRACER, state->daemon_pid, 0, 0, 0) != 0) { | ||
| if (!state->android_service_daemon |
There was a problem hiding this comment.
Bug: The Android service daemon skips the prctl(PR_SET_PTRACER) call, which can cause stack unwinding to fail and result in incomplete crash reports on some devices.
Severity: MEDIUM
Suggested Fix
Ensure that the service daemon has the necessary ptrace permissions. This could involve making the prctl(PR_SET_PTRACER) call even when in service daemon mode, or implementing an alternative mechanism to grant these permissions before the crash handler is initialized. The goal is to allow process_vm_readv to succeed.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: src/backends/sentry_backend_native.c#L1112-L1115
Potential issue: When the Android service daemon is enabled, the code intentionally
skips the `prctl(PR_SET_PTRACER)` call. This call is required to grant the daemon
process permission to trace the app process on systems with the Yama LSM enabled and
`ptrace_scope` set to a value greater than 0. Without this permission,
`libunwindstack`'s use of `process_vm_readv` will fail, preventing it from reading
process memory. This causes stack unwinding to fail silently, resulting in crash reports
with only a single frame instead of a full stack trace, significantly reducing their
usefulness.
8ce92af to
a99236e
Compare
|
| - name: Check out sentry-java | ||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| repository: jpnurmi/sentry-java ### TODO: getsentry/sentry-java | ||
| ref: feat/native-crash-service | ||
| path: sentry-java |
There was a problem hiding this comment.
Android E2E job runs mutable third-party fork code with secrets
The Android job checks out jpnurmi/sentry-java at branch feat/native-crash-service and executes its Gradle build while SENTRY_E2E_* secrets are present; pin a full commit SHA from a trusted repo (and prefer getsentry/sentry-java) before running that code with credentials.
Evidence
- The
androidjob checks outrepository: jpnurmi/sentry-javawith mutableref: feat/native-crash-service(not a 40-char SHA). - The emulator step then runs
python scripts/setup-android-e2e.py sentry-java, and that script invokesgradlewfrom the checked-out tree (subprocess.run(..., cwd=java)), so branch tip code executes on the runner. - The same step exports
SENTRY_E2E_DSN,SENTRY_E2E_AUTH_TOKEN,SENTRY_E2E_ORG, andSENTRY_E2E_PROJECTfrom repository secrets into the job environment. - Anyone who can push that fork branch (or compromise the account) can change executed build logic while those secrets are available.
Identified by Warden · security-review · S5S-U4D
95b1105 to
d4c36e4
Compare
68e5853 to
3a7ab68
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 4 total unresolved issues (including 3 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3a7ab68. Configure here.
| ctx, build_registers_from_ctx(ctx, SIZE_MAX)); | ||
| enrich_stacktrace(ctx, captured); | ||
| return captured; | ||
| } |
There was a problem hiding this comment.
Android unwind skips libunwindstack
High Severity
The daemon prefers a handler capture for the crashing thread whenever it contains a non-zero fault IP, and returns before sentry__crash_unwind_stack_libunwindstack runs. The Android handler always stores that fault address first and cannot run libunwindstack in-process, so typical crashes keep a one-frame or frame-pointer stack instead of the CFI unwind this change added.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 3a7ab68. Configure here.
Exercise minidump reporting and tombstone merging through the surviving crash service without restarting the app. Verify threads, debug images, user/release metadata, and Java/native frames in merged stacks. Build the fixture against the local native and Java SDKs in an isolated Maven repository and run both cases on API 36 in CI.
3a7ab68 to
5042761
Compare


Warning
WIP 🚧🔨⏳⛔
This enables the out-of-process native crash daemon on Android, including file-backed IPC, daemon packaging as
libsentry-crash.so, backend-owned daemon path resolution, and preload support for managed runtimes.The NDK integration now selects native crash reporting mode from the Android SDK tombstone merging setting: tombstone-enabled builds avoid minidumps because minidumps take precedence over native envelopes, while tombstone-disabled builds keep native-with-minidump for richer crash data.
This also adds Android daemon support for signal-handler chaining, crash envelope queueing,
libunwindstackunwinding, and focused Android integration coverage.