Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid unwind across extern "C" in thread_local::fast_local #112292

Merged
merged 1 commit into from
Jun 8, 2023

Conversation

thomcc
Copy link
Member

@thomcc thomcc commented Jun 4, 2023

This is a minimal fix for #112285, in case we want a simple patch that can be easily to backported if that's desirable.

(Note: I have another broader cleanup which I've mostly omitted from here to avoid clutter, except for the Cell change, which isn't needed to fix UB, but simplifies safety comments).

The only tier-1 target that this occurs on in a way that seems likely to cause problems in practice linux-gnu, although I believe some folks care about that platform somewhat 😉. I'm unsure how big of an issue this is. I've seen stuff like this behave quite badly, but there's a number of reasons to think this might actually be "fine in practice".

I've hedged my bets and assumed we'll backport this at least to beta but my feeling is that there's not enough evidence this is a problem worth backporting further than that.

More details

This issue seems to have existed since thread_local!'s const init functionality was added. It occurs if you have a const-initialized thread local for a type that needs_drop, the drop panics, and you're on a target with support for static thread locals. In this case, we will end up defining an extern "C" function in the user crate rather than in libstd, and because the user crate will not have #![feature(c_unwind)] enabled, their panic will not be caught by an auto-inserted abort guard.

In practice, the actual situation where problems are likely1 is somewhat narrower.

On most targets with static thread locals, we manage the TLS dtor list by hand (for reentrancy reasons among others). In these cases, while the users code may panic, we're calling it inside our own extern "C" (or extern "system") function, which seems to (at least in practice) catch the panic and convert it to an abort.

However, on a few targets, most notably linux-gnu with recent glibc (but also fuchsia and redox), a tls dtor registration mechanism exists which we can actually use directly, __cxa_thread_atexit_impl.

This is the case that seems most likely to be a cause for concern, as now we're passing a function to the system library and panicking out of it in a case where there are may not be Rust frames above it on the call stack (since it's running thread shutdown), and even if there were, it may not be prepared to handle such unwinding. If that's the case, it'd be bad.

Is it? Dunno. The fact that it's a __cxa_* function makes me think they probably have considered that the callback could throw but I have no evidence here and it doesn't seem to be written down anywhere, so it's just a guess. (I would not be surprised if someone comes into this thread to tell me how definitely-bad-news it is).

That said, as I said, all this is actually UB! If this isn't a "technically UB but fine in practice", but all bets are off if this is the kind of thing we are telling LLVM about.

Footnotes

  1. This is UB so take that with a grain of salt -- I'm absolutely making assumptions about how the UB will behave "in practice" here, which is almost certainly a mistake.

@rustbot
Copy link
Collaborator

rustbot commented Jun 4, 2023

r? @m-ou-se

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 4, 2023
/// fn` declared in a user crate). If the callback unwinds anyway, then
/// `rtabort` with a message about thread local panicking on drop.
#[inline]
pub fn abort_on_dtor_unwind(f: impl FnOnce()) {
Copy link
Member Author

Choose a reason for hiding this comment

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

This is here mostly because we need it and I'll use it in more places in the followup PR.

@Noratrieb Noratrieb added the beta-nominated Nominated for backporting to the compiler in the beta channel. label Jun 5, 2023
@m-ou-se
Copy link
Member

m-ou-se commented Jun 5, 2023

This change looks fine.

@bors r+

Note: I have another broader cleanup [..]

Oh, me too. We should probably have a chat to make sure we're not doing double work or working against each other. ^^'

@bors
Copy link
Contributor

bors commented Jun 5, 2023

📌 Commit 70e1dc9 has been approved by m-ou-se

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 5, 2023
@m-ou-se
Copy link
Member

m-ou-se commented Jun 5, 2023

(See also #110897

  • panic in destructor of const initialized thread local isn't caught

)

@thomcc
Copy link
Member Author

thomcc commented Jun 5, 2023

Oh, me too. We should probably have a chat to make sure we're not doing double work or working against each other. ^^'

Yeah, so my cleanup that I hope to have up later today is largely small-scale stuff compared to that. Mostly just better panic handling and avoiding cases where we do multiple TLS accesses (e.g. multiple __tls_getaddr/_tlv_bootstrap) for no reason.

I do have some comments I've been meaning to mention in that issue tho, I guess I'll do that

@m-ou-se m-ou-se removed the beta-nominated Nominated for backporting to the compiler in the beta channel. label Jun 7, 2023
@m-ou-se
Copy link
Member

m-ou-se commented Jun 7, 2023

We discussed this in the libs meeting just now. Since this isn't a recent regression and this doesn't seem to result in actual issues today (other than just an abort), this doesn't seem like a good candidate for backporting.

@bors
Copy link
Contributor

bors commented Jun 8, 2023

⌛ Testing commit 70e1dc9 with merge 8091736...

@bors
Copy link
Contributor

bors commented Jun 8, 2023

☀️ Test successful - checks-actions
Approved by: m-ou-se
Pushing 8091736 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Jun 8, 2023
@bors bors merged commit 8091736 into rust-lang:master Jun 8, 2023
@rustbot rustbot added this to the 1.72.0 milestone Jun 8, 2023
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (8091736): comparison URL.

Overall result: no relevant changes - no action needed

@rustbot label: -perf-regression

Instruction count

This benchmark run did not return any relevant results for this metric.

Max RSS (memory usage)

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
5.0% [4.5%, 5.6%] 2
Regressions ❌
(secondary)
3.3% [2.4%, 5.0%] 3
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-4.2% [-4.5%, -4.0%] 2
All ❌✅ (primary) 5.0% [4.5%, 5.6%] 2

Cycles

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-2.5% [-4.3%, -1.8%] 5
Improvements ✅
(secondary)
-3.2% [-3.8%, -2.5%] 4
All ❌✅ (primary) -2.5% [-4.3%, -1.8%] 5

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 647.317s -> 647.603s (0.04%)

@Noratrieb Noratrieb added the beta-nominated Nominated for backporting to the compiler in the beta channel. label Jun 12, 2023
@Noratrieb
Copy link
Member

Noratrieb commented Jun 12, 2023

nominating for beta backport: #112285 (comment)

@m-ou-se
Copy link
Member

m-ou-se commented Jun 14, 2023

nominating for beta backport: #112285 (comment)

See #112292 (comment)

@m-ou-se m-ou-se removed the beta-nominated Nominated for backporting to the compiler in the beta channel. label Jun 14, 2023
@Noratrieb
Copy link
Member

ah, didnt see that

STATE = 2;
$crate::ptr::drop_in_place(ptr);
}
$crate::thread::local_impl::abort_on_dtor_unwind(|| {
Copy link
Member

Choose a reason for hiding this comment

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

This can be removed again when we (finally) enable abort-on-unwind for all extern "C", right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants