Skip to content

Fix crash when a span is finished twice or used from multiple threads - #1609

Merged
tustanivsky merged 6 commits into
mainfrom
fix/native-tracing-finish-races
Oct 2, 2026
Merged

tustanivsky merged 6 commits into
mainfrom
fix/native-tracing-finish-races

Conversation

@tustanivsky

@tustanivsky tustanivsky commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

This PR fixes crashes on Windows, Linux and other sentry-native platforms when a span or transaction is finished twice, or finished on one thread while another thread is still using it.

sentry_span_finish / sentry_transaction_finish hand ownership to sentry-native, which frees the object. The plugin wrappers kept the stale pointer and only locked the tag/data setters, so:

  • calling Finish twice on a USentrySpan freed the native span twice and corrupted the heap. Unlike USentryTransaction, USentrySpan::Finish had no IsFinished() guard.
  • calling Finish on one thread while another called a setter, StartChild or GetTrace on the same span or transaction could use freed memory.

Key changes

  • FGenericPlatformSentrySpan / FGenericPlatformSentryTransaction take their lock around every native call and set the native pointer to null after finishing. Later calls are no-ops, and IsFinished() is now based on that pointer, replacing the separate flag.
  • USentrySpan::Finish / FinishWithTimestamp now check IsFinished(), as USentryTransaction already did.

On sentry-native platforms, finishing a span or transaction hands ownership
to the SDK, which frees it. The wrappers kept the stale pointer and only
locked the setters, so a second Finish, or Finish racing a setter, StartChild
or GetTrace on another thread, used freed memory.

Wrappers now take their lock for every native call and null the pointer on
finish; later calls are no-ops. USentrySpan::Finish gets the IsFinished guard
USentryTransaction already had.
@jpnurmi

jpnurmi commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator

If sentry_span_inc/decref were available, downstream wrappers could safely hold on to their span instances, but would finishing the same instance still result in strange issues? 🤔

@tustanivsky

Copy link
Copy Markdown
Collaborator Author

If sentry_span_inc/decref were available, downstream wrappers could safely hold on to their span instances, but would finishing the same instance still result in strange issues?

I think a double-finish guard makes sense regardless. Otherwise, a second finish would release another reference and repeat the finish work, no?

@jpnurmi jpnurmi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yeah, probably doesn't help much 🤦‍♂️

@tustanivsky
tustanivsky merged commit c1c6b76 into main Oct 2, 2026
61 checks passed
@tustanivsky
tustanivsky deleted the fix/native-tracing-finish-races branch October 2, 2026 13:23
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.

3 participants