fix(core): Prevent HubSwitchGuard panic at thread teardown#1241
Merged
Conversation
When a `HubSwitchGuard` is dropped, the `THREAD_HUB` is meant to be restored to its previous value. In the past, we performed this swap using `THREAD_HUB.with`, which panics if the `THREAD_HUB` thread-local has been destroyed, which can be the case during thread destruction. Essentially, if a `HubSwitchGuard` is stored in a thread-local until the thread terminates, it can happen that the `THREAD_HUB` is destroyed before the `HubSwitchGuard` is dropped, leading to a panic when the `HubSwitchGuard` is dropped. TLS drop order is not guaranteed by Rust, but, at least on macOS platforms, this behavior reliably occurs if the thread-local storing the `HubSwitchGuard` gets initialized before the `THREAD_HUB` thread-local variable. The solution here is simple: instead of using `THREAD_HUB.with`, we use `THREAD_HUB.try_with`, which returns an error rather than panicking in the case that the `THREAD_HUB` has been destroyed. We ignore any resulting errors because, if the `THREAD_HUB` thread-local slot has been destroyed, there is nothing to swap back to the original value, and this would anyways typically occur only when the thread is shutting down. We also add two regression tests, at least one of which should fail if the bug is reintroduced. As the TLS drop order is not guaranteed by the language, we test both initializing the guard slot before the `THREAD_HUB` (this reliably fails on macOS when the bug is introduced), and we also test initializing `THREAD_HUB` before the `HubSwitchGuard` slot (this reliably passes on macOS, even without the fix, but may fail on other platforms depending on implementation). Fixes [#1237](#1237) Fixes [RUST-264](https://linear.app/getsentry/issue/RUST-264)
szokeasaurusrex
force-pushed
the
szokeasaurusrex/panic-in-panic-fix
branch
from
July 14, 2026 08:30
2dfbe2e to
efabaf8
Compare
giortzisg
approved these changes
Jul 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When a
HubSwitchGuardis dropped, theTHREAD_HUBis meant to be restored to its previous value.In the past, we performed this swap using
THREAD_HUB.with, which panics if theTHREAD_HUBthread-local has been destroyed, which can be the case during thread destruction. Essentially, if aHubSwitchGuardis stored in a thread-local until the thread terminates, it can happen that theTHREAD_HUBis destroyed before theHubSwitchGuardis dropped, leading to a panic when theHubSwitchGuardis dropped. TLS drop order is not guaranteed by Rust, but, at least on macOS platforms, this behavior reliably occurs if the thread-local storing theHubSwitchGuardgets initialized before theTHREAD_HUBthread-local variable.The solution here is simple: instead of using
THREAD_HUB.with, we useTHREAD_HUB.try_with, which returns an error rather than panicking in the case that theTHREAD_HUBhas been destroyed. We ignore any resulting errors because, if theTHREAD_HUBthread-local slot has been destroyed, there is nothing to swap back to the original value, and this would anyways typically occur only when the thread is shutting down.We also add two regression tests, at least one of which should fail if the bug is reintroduced. As the TLS drop order is not guaranteed by the language, we test both initializing the guard slot before the
THREAD_HUB(this reliably fails on macOS when the bug is introduced), and we also test initializingTHREAD_HUBbefore theHubSwitchGuardslot (this reliably passes on macOS, even without the fix, but may fail on other platforms depending on implementation).Fixes #1237
Fixes RUST-264