Skip to content

poc: add heartbeat functionality to native backend#1742

Draft
bitsandfoxes wants to merge 2 commits into
masterfrom
feat/heartbeat
Draft

poc: add heartbeat functionality to native backend#1742
bitsandfoxes wants to merge 2 commits into
masterfrom
feat/heartbeat

Conversation

@bitsandfoxes
Copy link
Copy Markdown
Contributor

@bitsandfoxes bitsandfoxes commented May 22, 2026

Resolves https://github.com/getsentry/team-gdx/issues/155

Warning

WIP    🚧🔨⏳⛔

@github-actions
Copy link
Copy Markdown

Fails
🚫 Please consider adding a changelog entry for the next release.

Instructions and example for changelog

Please add an entry to CHANGELOG.md to the "Unreleased" section. Make sure the entry includes this PR's number.

Example:

## Unreleased

### Features

- add heartbeat functionality to native backend ([#1742](https://github.com/getsentry/sentry-native/pull/1742))

If none of the above apply, you can opt out of this check by adding #skip-changelog to the PR description or adding a skip-changelog label.

Generated by 🚫 dangerJS against 1f2c69d

Comment on lines +2748 to +2750
if (env_path) {
sentry_envelope_t *envelope = sentry__envelope_from_path(env_path);
if (envelope && options && options->transport) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: In capture_and_send_app_hang, an envelope allocated by sentry__envelope_from_path is leaked if options->transport is NULL, as the freeing logic is skipped.
Severity: MEDIUM

Suggested Fix

Ensure the envelope is always freed, regardless of whether sentry__capture_envelope is called. This can be achieved by moving the sentry_envelope_free call to a location that executes in all paths, or by adding an else block to handle the case where the transport is unavailable and free the envelope there.

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_daemon.c#L2748-L2750

Potential issue: In the `capture_and_send_app_hang` function, an envelope is allocated
from a file path using `sentry__envelope_from_path`. This envelope is intended to be
freed within `sentry__capture_envelope`. However, the call to `sentry__capture_envelope`
is conditional on `options->transport` being non-NULL. If transport initialization fails
and `options->transport` is `NULL`, the condition is false, the function is not called,
and the allocated envelope is never freed, resulting in a memory leak. Since the daemon
is a long-running process, this leak can accumulate over time.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 4 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1f2c69d. Configure here.

if (timer) {
wait_handles[1] = timer;
wait_count = 2;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Timer failure disables hangs

Medium Severity

If the Windows app-hang timer fails to initialize, the daemon won't set up its polling mechanism. This prevents app-hang detection from running, even when the feature is enabled and the host continues to send heartbeats.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1f2c69d. Configure here.

/* Always advance last_fired_hb, even if capture failed —
* prevents a retry storm against a wedged thread. The next
* heartbeat advance re-arms detection naturally. */
last_fired_hb = hb;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failed capture still cools down

Medium Severity

After SENTRY_APP_HANG_FIRE, the daemon always sets last_fired_hb to the current heartbeat even when capture_and_send_app_hang fails (for example OpenThread with a zero or invalid app_hang_target_tid). While the monitored thread stays frozen the heartbeat timestamp does not change, so later ticks hit the cooldown branch and no ApplicationNotResponding event is sent.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1f2c69d. Configure here.

Comment thread src/sentry_app_hang.c

/* Relaxed 64-bit store. On x64 this is a single mov. On x86 the value
* may tear, but that is OK — see the comment in sentry_crash_context.h. */
ctx->app_hang_last_heartbeat_ms = sentry__app_hang_now_ms();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heartbeat use after free

Medium Severity

sentry_app_hang_heartbeat copies g_app_hang_shmem into a local pointer, then writes shared heartbeat fields through it. During native_backend_shutdown, another thread can clear that global and unmap IPC between the load and the store, so a concurrent heartbeat can touch freed shared memory.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1f2c69d. Configure here.

}
sentry__path_remove(env_path);
sentry__path_free(env_path);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

App hang upload not flushed

High Severity

After an app-hang envelope is queued via sentry__capture_envelope, the daemon keeps running and never flushes its HTTP transport. Normal sentry_close() then terminates the daemon with TerminateProcess, so background sends can be cut off and the ApplicationNotResponding event may never reach Sentry.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1f2c69d. Configure here.

@bitsandfoxes bitsandfoxes marked this pull request as draft May 22, 2026 11:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant