Skip to content

Commit 7398628

Browse files
jpnurmiclaude
andcommitted
ref: move user_consent to sentry_run_t for thread-safe access
Move require_user_consent and user_consent from sentry_options_t to sentry_run_t as atomic longs. Add sentry__run_should_skip_upload() helper that batcher and retry call directly through their refcounted run pointer, replacing the fragile raw long* into options. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent df20646 commit 7398628

File tree

9 files changed

+35
-23
lines changed

9 files changed

+35
-23
lines changed

src/sentry_batcher.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,7 @@ sentry__batcher_flush(sentry_batcher_t *batcher, bool crash_safe)
224224
// crash
225225
sentry__run_write_envelope(batcher->run, envelope);
226226
sentry_envelope_free(envelope);
227-
} else if (!batcher->user_consent
228-
|| sentry__atomic_fetch(batcher->user_consent)
229-
== SENTRY_USER_CONSENT_GIVEN) {
227+
} else if (!sentry__run_should_skip_upload(batcher->run)) {
230228
// Normal operation: use transport for HTTP transmission
231229
sentry__transport_send_envelope(batcher->transport, envelope);
232230
} else {
@@ -373,12 +371,10 @@ sentry__batcher_startup(
373371
{
374372
// dsn is incref'd because release() decref's it and may outlive options.
375373
batcher->dsn = sentry__dsn_incref(options->dsn);
376-
// transport, run, and user_consent are non-owning refs, safe because they
374+
// transport and run are non-owning refs, safe because they
377375
// are only accessed in flush() which is bound by the options lifetime.
378376
batcher->transport = options->transport;
379377
batcher->run = options->run;
380-
batcher->user_consent
381-
= options->require_user_consent ? (long *)&options->user_consent : NULL;
382378

383379
// Mark thread as starting before actually spawning so thread can transition
384380
// to RUNNING. This prevents shutdown from thinking the thread was never

src/sentry_batcher.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ typedef struct {
4747
sentry_dsn_t *dsn;
4848
sentry_transport_t *transport;
4949
sentry_run_t *run;
50-
long *user_consent; // (atomic) NULL if consent not required
5150
} sentry_batcher_t;
5251

5352
typedef struct {

src/sentry_core.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,13 @@ load_user_consent(sentry_options_t *opts)
7979
sentry__path_free(consent_path);
8080
switch (contents ? contents[0] : 0) {
8181
case '1':
82-
opts->user_consent = SENTRY_USER_CONSENT_GIVEN;
82+
opts->run->user_consent = SENTRY_USER_CONSENT_GIVEN;
8383
break;
8484
case '0':
85-
opts->user_consent = SENTRY_USER_CONSENT_REVOKED;
85+
opts->run->user_consent = SENTRY_USER_CONSENT_REVOKED;
8686
break;
8787
default:
88-
opts->user_consent = SENTRY_USER_CONSENT_UNKNOWN;
88+
opts->run->user_consent = SENTRY_USER_CONSENT_UNKNOWN;
8989
break;
9090
}
9191
sentry_free(contents);
@@ -96,9 +96,7 @@ sentry__should_skip_upload(void)
9696
{
9797
bool skip = true;
9898
SENTRY_WITH_OPTIONS (options) {
99-
skip = options->require_user_consent
100-
&& sentry__atomic_fetch((long *)&options->user_consent)
101-
!= SENTRY_USER_CONSENT_GIVEN;
99+
skip = sentry__run_should_skip_upload(options->run);
102100
}
103101
return skip;
104102
}
@@ -204,6 +202,7 @@ sentry_init(sentry_options_t *options)
204202
SENTRY_WARN("failed to initialize run directory");
205203
goto fail;
206204
}
205+
options->run->require_user_consent = options->require_user_consent;
207206

208207
load_user_consent(options);
209208

@@ -434,7 +433,7 @@ static void
434433
set_user_consent(sentry_user_consent_t new_val)
435434
{
436435
SENTRY_WITH_OPTIONS (options) {
437-
if (sentry__atomic_store((long *)&options->user_consent, new_val)
436+
if (sentry__atomic_store(&options->run->user_consent, new_val)
438437
!= new_val) {
439438
if (options->backend
440439
&& options->backend->user_consent_changed_func) {
@@ -483,7 +482,7 @@ sentry_user_consent_get(void)
483482
sentry_user_consent_t rv = SENTRY_USER_CONSENT_UNKNOWN;
484483
SENTRY_WITH_OPTIONS (options) {
485484
rv = (sentry_user_consent_t)(int)sentry__atomic_fetch(
486-
(long *)&options->user_consent);
485+
&options->run->user_consent);
487486
}
488487
return rv;
489488
}

src/sentry_core.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
/**
3535
* This function will check the user consent, and return `true` if uploads
3636
* should *not* be sent to the sentry server, and be discarded instead.
37+
*
38+
* This acquires the options lock internally. Use
39+
* `sentry__run_should_skip_upload` from worker threads that may run while
40+
* the options are locked during SDK shutdown.
3741
*/
3842
bool sentry__should_skip_upload(void);
3943

src/sentry_database.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ sentry__run_new(const sentry_path_t *database_path)
7474
}
7575

7676
run->refcount = 1;
77+
run->require_user_consent = 0;
78+
run->user_consent = SENTRY_USER_CONSENT_UNKNOWN;
7779
run->uuid = uuid;
7880
run->run_path = run_path;
7981
run->session_path = session_path;
@@ -96,6 +98,14 @@ sentry__run_new(const sentry_path_t *database_path)
9698
return NULL;
9799
}
98100

101+
bool
102+
sentry__run_should_skip_upload(const sentry_run_t *run)
103+
{
104+
return sentry__atomic_fetch((long *)&run->require_user_consent)
105+
&& sentry__atomic_fetch((long *)&run->user_consent)
106+
!= SENTRY_USER_CONSENT_GIVEN;
107+
}
108+
99109
sentry_run_t *
100110
sentry__run_incref(sentry_run_t *run)
101111
{

src/sentry_database.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,19 @@ typedef struct sentry_run_s {
1414
sentry_path_t *cache_path;
1515
sentry_filelock_t *lock;
1616
long refcount;
17+
long require_user_consent;
18+
long user_consent;
1719
} sentry_run_t;
1820

21+
/**
22+
* This function will check the user consent, and return `true` if uploads
23+
* should *not* be sent to the sentry server, and be discarded instead.
24+
*
25+
* This is a lock-free variant of `sentry__should_skip_upload`, safe to call
26+
* from worker threads while the options are locked during SDK shutdown.
27+
*/
28+
bool sentry__run_should_skip_upload(const sentry_run_t *run);
29+
1930
/**
2031
* This creates a new application run including its associated directory and
2132
* lockfile:

src/sentry_options.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ sentry_options_new(void)
4646
}
4747
sentry_options_set_sdk_name(opts, SENTRY_SDK_NAME);
4848
opts->max_breadcrumbs = SENTRY_BREADCRUMBS_MAX;
49-
opts->user_consent = SENTRY_USER_CONSENT_UNKNOWN;
5049
opts->auto_session_tracking = true;
5150
opts->system_crash_reporter_enabled = false;
5251
opts->attach_screenshot = false;

src/sentry_options.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ struct sentry_options_s {
8585
struct sentry_backend_s *backend;
8686
sentry_session_t *session;
8787

88-
long user_consent;
8988
long refcount;
9089
uint64_t shutdown_timeout;
9190
sentry_handler_strategy_t handler_strategy;

src/sentry_retry.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ typedef enum {
2828
struct sentry_retry_s {
2929
sentry_run_t *run;
3030
bool cache_keep;
31-
long *user_consent;
3231
uint64_t startup_time;
3332
volatile long state;
3433
volatile long scheduled;
@@ -49,8 +48,6 @@ sentry__retry_new(const sentry_options_t *options)
4948
sentry__mutex_init(&retry->sealed_lock);
5049
retry->run = sentry__run_incref(options->run);
5150
retry->cache_keep = options->cache_keep;
52-
retry->user_consent
53-
= options->require_user_consent ? (long *)&options->user_consent : NULL;
5451
retry->startup_time = sentry__usec_time() / 1000;
5552
return retry;
5653
}
@@ -145,9 +142,7 @@ size_t
145142
sentry__retry_send(sentry_retry_t *retry, uint64_t before,
146143
sentry_retry_send_func_t send_cb, void *data)
147144
{
148-
if (retry->user_consent
149-
&& sentry__atomic_fetch(retry->user_consent)
150-
!= SENTRY_USER_CONSENT_GIVEN) {
145+
if (sentry__run_should_skip_upload(retry->run)) {
151146
return 0;
152147
}
153148

0 commit comments

Comments
 (0)