Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2910fcb
refactor(scope): hide direct data access
jpnurmi Jul 22, 2026
592cfe0
WIP: observers
jpnurmi Jul 27, 2026
de089e3
feat(sync): add platform rwlock primitive
jpnurmi Aug 5, 2026
2db6aa8
refactor(sync): make rwlock operations inline
jpnurmi Aug 5, 2026
85ea15b
refactor(scope): guard simple fields with rwlock
jpnurmi Aug 5, 2026
1cebda0
refactor(scope): retain user and fingerprint values safely
jpnurmi Aug 5, 2026
ff0b6d4
refactor(scope): store string fields as values
jpnurmi Aug 5, 2026
691d2ac
refactor(scope): move locked payload into scope data
jpnurmi Aug 6, 2026
e0436b5
refactor(scope): hide direct scope data access
jpnurmi Aug 6, 2026
af5cffd
ref containers
jpnurmi Aug 6, 2026
88e6162
breadcrumbs
jpnurmi Aug 7, 2026
22476af
trace_context
jpnurmi Aug 7, 2026
95a44ac
propagation_context
jpnurmi Aug 7, 2026
48f09d3
dsc
jpnurmi Aug 7, 2026
7ab213c
span/transaction_object
jpnurmi Aug 7, 2026
59ae8b0
restore
jpnurmi Aug 7, 2026
7356f20
lock observers
jpnurmi Aug 7, 2026
777bba3
finally :D
jpnurmi Aug 7, 2026
f6e3d85
fix formatting
jpnurmi Aug 7, 2026
2e9f497
fix(scope): Keep global scope alive during access
jpnurmi Aug 9, 2026
5aaba3d
restore locks for attachments
jpnurmi Aug 12, 2026
d530e7a
clone (cow) attachments guard against concurrent modifications
jpnurmi Aug 12, 2026
3c2dcd5
clean up
jpnurmi Aug 18, 2026
1452b9e
fix concurrent init
jpnurmi Aug 18, 2026
5344fd9
breadcrumbs: fix use-after-free
jpnurmi Aug 18, 2026
28113fd
fix(attachments): Notify backends through scope observers
jpnurmi Aug 19, 2026
ba539a7
fix cleanup_observers
jpnurmi Aug 19, 2026
fd41b34
load
jpnurmi Aug 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ IndentPPDirectives: AfterHash
ColumnLimit: 80
AlwaysBreakAfterDefinitionReturnType: All
PointerAlignment: Right
ForEachMacros: ['SENTRY_WITH_SCOPE', 'SENTRY_WITH_SCOPE_MUT', 'SENTRY_WITH_SCOPE_MUT_NO_FLUSH', 'SENTRY_WITH_OPTIONS', 'SENTRY_WITH_OPTIONS_MUT']
ForEachMacros: ['SENTRY_WITH_SCOPE', 'SENTRY_WITH_SCOPE_MUT', 'SENTRY_WITH_SCOPE_MUT_NO_FLUSH', 'SENTRY_WITH_OPTIONS', 'SENTRY_WITH_OPTIONS_MUT', 'SENTRY_SCOPE_READ_LOCK', 'SENTRY_SCOPE_WRITE_LOCK']
InsertNewlineAtEOF: True
22 changes: 13 additions & 9 deletions src/backends/sentry_backend_crashpad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context)
// written above and stays breadcrumb-free
SENTRY_WITH_SCOPE (scope) {
sentry_value_set_by_key(crash_event, "breadcrumbs",
sentry__ringbuffer_to_list(scope->breadcrumbs));
sentry__scope_breadcrumbs_to_list(scope));
}

sentry__session_replay_flush_pending(
Expand Down Expand Up @@ -1168,10 +1168,9 @@ make_attachment_path(const sentry_path_t *run_path, sentry_value_t attachment)
}

static void
crashpad_backend_add_attachment(sentry_backend_t *backend,
sentry_value_t attachment, const sentry_options_t *UNUSED(options))
crashpad_backend_add_attachment(void *state, sentry_value_t attachment)
{
auto *data = static_cast<crashpad_state_t *>(backend->data);
auto *data = static_cast<crashpad_state_t *>(state);
if (!data || !data->client) {
return;
}
Expand Down Expand Up @@ -1200,10 +1199,9 @@ crashpad_backend_add_attachment(sentry_backend_t *backend,
}

static void
crashpad_backend_remove_attachment(
sentry_backend_t *backend, sentry_value_t attachment)
crashpad_backend_remove_attachment(void *state, sentry_value_t attachment)
{
auto *data = static_cast<crashpad_state_t *>(backend->data);
auto *data = static_cast<crashpad_state_t *>(state);
if (!data || !data->client) {
return;
}
Expand Down Expand Up @@ -1259,8 +1257,14 @@ sentry__backend_new(void)
backend->prune_database_func = crashpad_backend_prune_database;
#if defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_LINUX) \
|| defined(SENTRY_PLATFORM_MACOS)
backend->add_attachment_func = crashpad_backend_add_attachment;
backend->remove_attachment_func = crashpad_backend_remove_attachment;
backend->scope_observer = sentry__scope_observer_new();
if (backend->scope_observer) {
backend->scope_observer->data = data;
backend->scope_observer->add_attachment
= crashpad_backend_add_attachment;
backend->scope_observer->remove_attachment
= crashpad_backend_remove_attachment;
}
#endif
backend->data = data;
backend->can_capture_after_shutdown = true;
Expand Down
27 changes: 20 additions & 7 deletions src/backends/sentry_backend_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ wer_register_module(uint64_t app_tid)
typedef struct {
sentry_crash_ipc_t *ipc;
pid_t daemon_pid;
sentry_path_t *run_path;
sentry_path_t *event_path;
sentry_path_t *breadcrumb1_path;
sentry_path_t *breadcrumb2_path;
Expand Down Expand Up @@ -244,6 +245,10 @@ native_backend_startup(
return 1;
}
backend->data = state;
state->run_path = sentry__path_clone(options->run->run_path);
if (backend->scope_observer) {
backend->scope_observer->data = state;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Startup failure leaks native run path

Medium Severity

native_backend_startup clones run_path onto backend state, then on IPC or context-setup failure it sentry_frees that state without sentry__path_free. The cloned path is leaked, and scope_observer->data can still point at the freed state.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fd41b34. Configure here.


// Initialize IPC (protected by global synchronization for concurrent
// access)
Expand Down Expand Up @@ -715,6 +720,7 @@ native_backend_free(sentry_backend_t *backend)
sentry__path_free(state->breadcrumb1_path);
sentry__path_free(state->breadcrumb2_path);
sentry__path_free(state->envelope_path);
sentry__path_free(state->run_path);

sentry_free(state);
}
Expand Down Expand Up @@ -753,12 +759,14 @@ native_backend_write_attachments(const sentry_path_t *event_path)
return;
}
SENTRY_WITH_SCOPE (scope) {
sentry_value_t attachments = scope->attachments;
sentry_value_t attachments = sentry__scope_load_attachments(scope);
if (sentry_value_get_length(attachments) == 0) {
sentry_value_decref(attachments);
continue;
}
sentry_path_t *run_path = sentry__path_dir(event_path);
if (!run_path) {
sentry_value_decref(attachments);
continue;
}
sentry_path_t *attach_list_path
Expand Down Expand Up @@ -807,6 +815,7 @@ native_backend_write_attachments(const sentry_path_t *event_path)
sentry__path_free(attach_list_path);
}
sentry__path_free(run_path);
sentry_value_decref(attachments);
}
}

Expand Down Expand Up @@ -931,18 +940,19 @@ native_backend_add_breadcrumb(sentry_backend_t *backend,
}

static void
native_backend_add_attachment(sentry_backend_t *backend,
sentry_value_t attachment, const sentry_options_t *options)
native_backend_add_attachment(void *data, sentry_value_t attachment)
{
(void)backend; // Unused
native_backend_state_t *state = (native_backend_state_t *)data;
if (!state) {
return;
}

// For buffer attachments, derive a path in the run directory and write to
// disk
size_t bytes_len = 0;
const char *bytes = sentry__attachment_get_bytes(attachment, &bytes_len);
if (bytes) {
sentry_path_t *path
= make_attachment_path(options->run->run_path, attachment);
sentry_path_t *path = make_attachment_path(state->run_path, attachment);
if (!path) {
const char *filename = sentry__attachment_get_filename(attachment);
SENTRY_WARNF("failed to create path for native backend attachment "
Expand Down Expand Up @@ -1137,7 +1147,10 @@ sentry__backend_new(void)
backend->except_func = native_backend_except;
backend->flush_scope_func = native_backend_flush_scope;
backend->add_breadcrumb_func = native_backend_add_breadcrumb;
backend->add_attachment_func = native_backend_add_attachment;
backend->scope_observer = sentry__scope_observer_new();
if (backend->scope_observer) {
backend->scope_observer->add_attachment = native_backend_add_attachment;
}
backend->user_consent_changed_func = native_backend_user_consent_changed;
backend->can_capture_after_shutdown = false;

Expand Down
38 changes: 21 additions & 17 deletions src/integrations/sentry_integration_wer.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,18 @@ wer_remove_attachment(void *UNUSED(data), sentry_value_t attachment)
}
}

static void
wer_for_each_attachment(
sentry_scope_t *scope, void *data, void (*callback)(void *, sentry_value_t))
{
sentry_value_t attachments = sentry__scope_load_attachments(scope);
size_t len = sentry_value_get_length(attachments);
for (size_t i = 0; i < len; i++) {
callback(data, sentry_value_get_by_index(attachments, i));
}
sentry_value_decref(attachments);
}

static void
wer_cleanup_tag(const char *key, sentry_value_t UNUSED(value), void *data)
{
Expand All @@ -207,13 +219,11 @@ wer_clear(void *data)
return;
}

sentry__value_foreach_key_value(scope->tags, wer_cleanup_tag, wer_data);
sentry_value_t tags = sentry__scope_load_tags(scope);
sentry__value_foreach_key_value(tags, wer_cleanup_tag, wer_data);
sentry_value_decref(tags);
Comment thread
cursor[bot] marked this conversation as resolved.

size_t len = sentry_value_get_length(scope->attachments);
for (size_t i = 0; i < len; i++) {
wer_remove_attachment(
wer_data, sentry_value_get_by_index(scope->attachments, i));
}
wer_for_each_attachment(scope, wer_data, wer_remove_attachment);
}

static void
Expand All @@ -238,11 +248,7 @@ register_wer(
if (sentry__scope_add_observer(scope, observer)) {
wer_data->scope = scope;
wer_data->observer = observer;
size_t len = sentry_value_get_length(scope->attachments);
for (size_t i = 0; i < len; i++) {
wer_add_attachment(
wer_data, sentry_value_get_by_index(scope->attachments, i));
}
wer_for_each_attachment(scope, wer_data, wer_add_attachment);
}
}

Expand All @@ -256,13 +262,11 @@ unregister_wer(
return;
}

sentry__value_foreach_key_value(scope->tags, wer_cleanup_tag, wer_data);
sentry_value_t tags = sentry__scope_load_tags(scope);
sentry__value_foreach_key_value(tags, wer_cleanup_tag, wer_data);
sentry_value_decref(tags);

size_t len = sentry_value_get_length(scope->attachments);
for (size_t i = 0; i < len; i++) {
wer_remove_attachment(
wer_data, sentry_value_get_by_index(scope->attachments, i));
}
wer_for_each_attachment(scope, wer_data, wer_remove_attachment);

sentry__scope_remove_observer(scope, wer_data->observer);
wer_data->scope = NULL;
Expand Down
1 change: 1 addition & 0 deletions src/sentry_backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ sentry__backend_free(sentry_backend_t *backend)
if (backend->free_func) {
backend->free_func(backend);
}
sentry_free(backend->scope_observer);
sentry_free(backend);
}
4 changes: 1 addition & 3 deletions src/sentry_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ struct sentry_backend_s {
void (*user_consent_changed_func)(sentry_backend_t *);
uint64_t (*get_last_crash_func)(sentry_backend_t *);
void (*prune_database_func)(sentry_backend_t *);
void (*add_attachment_func)(
sentry_backend_t *, sentry_value_t, const sentry_options_t *options);
void (*remove_attachment_func)(sentry_backend_t *, sentry_value_t);
sentry_scope_observer_t *scope_observer;
void *data;
// Whether this backend still runs after shutdown_func was called.
bool can_capture_after_shutdown;
Expand Down
Loading
Loading