Skip to content

Support inlining cross-crate TLS access on MSVC #84933

Closed
@alexcrichton

Description

@alexcrichton

There exists a __getit function as part of the thread_local! implementation in the standard library. On the MSVC target this function is not #[inline], meaning that it can't get inlined across crates. This issue is about fixing that, for some scenarios, in the future.

The #[inline] attribute was added in #84876 and, like historical attempts it does not apply the attribute for MSVC targets. The reason for this is that MSVC appears to not support importing thread-local variables across a DLL boundary.

For example this C code:

__declspec(dllimport, thread) extern int a;

int get() {
    return a;
}

yields this error when compiled by Clang:

<source>:1:42: error: 'a' cannot be thread local when declared 'dllimport'
__declspec(dllimport, thread) extern int a;
                                         ^
1 error generated.

I do not personally know the history of this. Empirically this appears to be true, if #[inline] is applied to __getit then the compiler segfaults on MSVC. The Rust compiler generally applies dllimport for you and tries to infer when this would otherwise happen, which probably makes matters worse here.

To reproduce this in Rust it's relatively simple. First you'll need to acquire a patched compiler which applies #[inline] to the __getit function, then compile a library:

$ cat driver.rs
pub fn go() {
    std::collections::HashMap::<i32, i32>::new();
}
$ rustc driver.rs --crate-type dylib
$ cat main.rs
fn main() {
    driver::go();
}
$ rustc main.rs --extern driver=driver.dll

This binary will nondeterministically crash. The crash signature is variable, too. Here the HashMap constructor currently uses thread locals internally which is what triggers this bug.

In any case things appear to not work with #[inline], notably across DLL boundaries. What can work, however, is inlining thread local accesses that don't cross DLL boundaries. Ideally we would have some sort of conditional #[inline] attribute for this. Nothing of this form exists in rustc today, and implementing this is definitely quite a stretch. In any case though I wanted to file an issue about this possible improvement to libstd.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-thread-localsArea: Thread local storage (TLS)O-windows-msvcToolchain: MSVC, Operating system: Windows

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions