Skip to content

ref(value)!: atomic decref result check#1763

Open
jpnurmi wants to merge 4 commits into
masterfrom
jpnurmi/ref/refcount
Open

ref(value)!: atomic decref result check#1763
jpnurmi wants to merge 4 commits into
masterfrom
jpnurmi/ref/refcount

Conversation

@jpnurmi
Copy link
Copy Markdown
Collaborator

@jpnurmi jpnurmi commented May 27, 2026

Note

SC/BC break (low impact)

Fixes TOCTOU races in sentry__transaction_context_free, sentry__transaction_decref and sentry__span_decref by adding return value for sentry_value_decref indicating whether the value still has references, has been freed, or is primitive that needs no tracking:

if (!sentry_value_decref(value)) {
  free(related_resources);
}

While taking the BC/SC break hit, make sentry_value_incref return the incref'd value for convenience, to avoid reducing such boilerplate:

// before
sentry_value_incref(value);
do_something(value);

// after
do_something(sentry_value_incref(value));
Transaction and span refcount decrement has TOCTOU race

Details

sentry__transaction_decref (lines 352-364) and sentry__span_decref (lines 375-388) implement non-atomic check-then-act on the reference count. The code reads the refcount, compares it to 1, and if equal, proceeds to free the object. Between the read and the free, another thread could increment the refcount (via incref), creating a use-after-free. Alternatively, two concurrent decref calls could both read refcount=2, both decrement to 1, and neither triggers the free, causing a memory leak. Or both read refcount=1 and both free, causing a double-free.

Location

src/sentry_tracing.c:352

Impact

Double-free or use-after-free from concurrent refcount operations.

Reproduction steps

  1. Thread A calls sentry__transaction_decref, reads refcount=1, and is about to free. Thread B calls sentry__transaction_incref, incrementing refcount to 2. Thread A proceeds to free the transaction. Thread B now holds a dangling pointer. When Thread B later decrefs, it accesses freed memory, causing a use-after-free that could lead to code execution.

Recommended fix

Use atomic decrement (e.g., __atomic_sub_fetch) and check the result atomically, ensuring the free decision is based on the atomic operation's return value.


Severity: MEDIUM
Status: Open
Category: Race Condition
Repository: getsentry/sentry-native
Branch: master

@jpnurmi jpnurmi force-pushed the jpnurmi/ref/refcount branch from 1f48fb6 to 654a646 Compare May 27, 2026 11:18
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