Skip to content

Commit 2f506e6

Browse files
author
Yuki Okushi
authored
Rollup merge of #101368 - thomcc:wintls-noinline, r=ChrisDenton
Forbid inlining `thread_local!`'s `__getit` function on Windows Sadly, this will make things slower to avoid UB in an edge case, but it seems hard to avoid... and really whenever I look at this code I can't help but think we're asking for trouble. It's pretty dodgy for us to leave this as a normal function rather than `#[inline(never)]`, given that if it *does* get inlined into a dynamically linked component, it's extremely unsafe (you get some other thread local, or if you're lucky, crash). Given that it's pretty rare for people to use dylibs on Windows, the fact that we haven't gotten bug reports about it isn't really that convincing. Ideally we'd come up with some kind of compiler solution (that avoids paying for this cost when static linking, or *at least* for use within the same crate...), but it's not clear what that looks like. Oh, and because all this is only needed when we're implementing `thread_local!` with `#[thread_local]`, this patch adjusts the `cfg_attr` to be `all(windows, target_thread_local)` as well. r? ``@ChrisDenton`` See also #84933, which is about improving the situation.
2 parents e221616 + 3099dfd commit 2f506e6

File tree

1 file changed

+16
-9
lines changed

1 file changed

+16
-9
lines changed

library/std/src/thread/local.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ macro_rules! thread_local {
181181
macro_rules! __thread_local_inner {
182182
// used to generate the `LocalKey` value for const-initialized thread locals
183183
(@key $t:ty, const $init:expr) => {{
184-
#[cfg_attr(not(windows), inline)] // see comments below
184+
#[cfg_attr(not(all(windows, target_thread_local)), inline)] // see comments below
185+
#[cfg_attr(all(windows, target_thread_local), inline(never))]
185186
#[deny(unsafe_op_in_unsafe_fn)]
186187
unsafe fn __getit(
187188
_init: $crate::option::Option<&mut $crate::option::Option<$t>>,
@@ -294,12 +295,17 @@ macro_rules! __thread_local_inner {
294295
fn __init() -> $t { $init }
295296

296297
// When reading this function you might ask "why is this inlined
297-
// everywhere other than Windows?", and that's a very reasonable
298-
// question to ask. The short story is that it segfaults rustc if
299-
// this function is inlined. The longer story is that Windows looks
300-
// to not support `extern` references to thread locals across DLL
301-
// boundaries. This appears to at least not be supported in the ABI
302-
// that LLVM implements.
298+
// everywhere other than Windows?", and "why must it not be inlined
299+
// on Windows?" and these are very reasonable questions to ask.
300+
//
301+
// The short story is that Windows doesn't support referencing
302+
// `#[thread_local]` across DLL boundaries. The slightly longer
303+
// story is that each module (dll or exe) has its own separate set
304+
// of static thread locals, so if you try and reference a
305+
// `#[thread_local]` that comes from `crate1.dll` from within one of
306+
// `crate2.dll`'s functions, then it might give you a completely
307+
// different thread local than what you asked for (or it might just
308+
// crash).
303309
//
304310
// Because of this we never inline on Windows, but we do inline on
305311
// other platforms (where external references to thread locals
@@ -314,8 +320,9 @@ macro_rules! __thread_local_inner {
314320
// Cargo question kinda). This means that, unfortunately, Windows
315321
// gets the pessimistic path for now where it's never inlined.
316322
//
317-
// The issue of "should enable on Windows sometimes" is #84933
318-
#[cfg_attr(not(windows), inline)]
323+
// The issue of "should improve things on Windows" is #84933
324+
#[cfg_attr(not(all(windows, target_thread_local)), inline)]
325+
#[cfg_attr(all(windows, target_thread_local), inline(never))]
319326
unsafe fn __getit(
320327
init: $crate::option::Option<&mut $crate::option::Option<$t>>,
321328
) -> $crate::option::Option<&'static $t> {

0 commit comments

Comments
 (0)