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

Miri sometimes reports memory leak in thread-local storage on *-pc-windows-gnu #123583

Closed
RalfJung opened this issue Apr 7, 2024 · 24 comments · Fixed by #123937 or #124281
Closed

Miri sometimes reports memory leak in thread-local storage on *-pc-windows-gnu #123583

RalfJung opened this issue Apr 7, 2024 · 24 comments · Fixed by #123937 or #124281
Labels
A-miri Area: The miri tool A-thread-locals Area: Thread local storage (TLS) C-bug Category: This is a bug. O-windows Operating system: Windows

Comments

@RalfJung
Copy link
Member

RalfJung commented Apr 7, 2024

I've only seen this once, even though the test should be covered by miri-test-libstd every day:

  error: memory leaked: alloc26870878 (Rust heap, size: 8, align: 4), allocated here:
  Error:     --> /checkout/library/alloc/src/alloc.rs:100:9
       |
  100  |         __rust_alloc(layout.size(), layout.align())
       |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
       |
       = note: BACKTRACE:
       = note: inside `realstd::alloc::alloc` at /checkout/library/alloc/src/alloc.rs:100:9: 100:52
       = note: inside `realstd::alloc::Global::alloc_impl` at /checkout/library/alloc/src/alloc.rs:183:73: 183:86
       = note: inside `<realstd::alloc::Global as core::alloc::Allocator>::allocate` at /checkout/library/alloc/src/alloc.rs:243:9: 243:39
       = note: inside `alloc_crate::alloc::exchange_malloc` at /checkout/library/alloc/src/alloc.rs:332:11: 332:34
       = note: inside `realstd::boxed::Box::<realstd::sys::thread_local::os_local::Value<u8>>::new` at /checkout/library/alloc/src/boxed.rs:218:9: 218:20
       = note: inside `realstd::thread::local_impl::Key::<u8>::try_initialize::<{closure@/checkout/library/std/src/sys/thread_local/os_local.rs:28:27: 28:34}>` at /checkout/library/std/src/sys/thread_local/os_local.rs:145:37: 145:94
       = note: inside `realstd::thread::local_impl::Key::<u8>::get::<{closure@/checkout/library/std/src/sys/thread_local/os_local.rs:28:27: 28:34}>` at /checkout/library/std/src/sys/thread_local/os_local.rs:127:18: 127:43
  note: inside `sync::reentrant_lock::current_thread_unique_ptr::X::__getit`
      --> /checkout/library/std/src/sys/thread_local/os_local.rs:28:17
       |
  11   |   pub macro thread_local_inner {
       |   ----------------------------
       |   |
       |   in this expansion of `$crate::thread::local_impl::thread_local_inner!` (#2)
       |   in this expansion of `$crate::thread::local_impl::thread_local_inner!` (#3)
  ...
  28   | /                 __KEY.get(move || {
  29   | |                     if let $crate::option::Option::Some(init) = _init {
  30   | |                         if let $crate::option::Option::Some(value) = init.take() {
  31   | |                             return value;
  ...    |
  36   | |                     __init()
  37   | |                 })
       | |__________________^
  ...
  82   |               $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
       |               ------------------------------------------------------------------- in this macro invocation (#3)
       |
      ::: library/std/src/sync/reentrant_lock.rs:318:5
       |
  318  |       thread_local! { static X: u8 = const { 0 } }
       |       -------------------------------------------- in this macro invocation (#1)
       |
      ::: library/std/src/thread/local.rs:183:1
       |
  183  | / macro_rules! thread_local {
  184  | |     // empty (base case for the recursion)
  185  | |     () => {};
  ...    |
  193  | |         $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
       | |         ----------------------------------------------------------------------------------------- in this macro invocation (#2)
  ...    |
  205  | |     );
  206  | | }
       | |_- in this expansion of `thread_local!` (#1)
       = note: inside `realstd::thread::LocalKey::<u8>::try_with::<{closure@library/std/src/sync/reentrant_lock.rs:319:12: 319:15}, usize>` at /checkout/library/std/src/thread/local.rs:283:32: 283:50
       = note: inside `realstd::thread::LocalKey::<u8>::with::<{closure@library/std/src/sync/reentrant_lock.rs:319:12: 319:15}, usize>` at /checkout/library/std/src/thread/local.rs:260:9: 260:25
  note: inside `sync::reentrant_lock::current_thread_unique_ptr`
      --> library/std/src/sync/reentrant_lock.rs:319:5
       |
  319  |     X.with(|x| <*const _>::addr(x))
       |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  note: inside `sync::reentrant_lock::ReentrantLock::<()>::lock`
      --> library/std/src/sync/reentrant_lock.rs:184:27
       |
  184  |         let this_thread = current_thread_unique_ptr();
       |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  note: inside `sync::reentrant_lock::tests::smoke`
      --> library/std/src/sync/reentrant_lock/tests.rs:10:17
       |
  10   |         let a = l.lock();
       |                 ^^^^^^^^
  note: inside closure
      --> library/std/src/sync/reentrant_lock/tests.rs:7:11
       |
  6    | #[test]
       | ------- in this procedural macro expansion
  7    | fn smoke() {
       |           ^
       |
      ::: /checkout/library/core/src/macros/mod.rs:1636:5
       |
  1636 |     pub macro test($item:item) {
       |     -------------- in this expansion of `#[test]`

Cc @joboet @m-ou-se @Amanieu

@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Apr 7, 2024
@RalfJung
Copy link
Member Author

RalfJung commented Apr 7, 2024

Or maybe this is caused by Miri not properly running the on-thread-exit hook on Windows? The support for that is a bit fragile as Miri does not support these magic linker sections we rely on. Instead Miri hard-codes the path to this static and calls it. But with the test crate we may have that static twice (once in std and once in the test crate) and only one of them gets called...

However I would expect that this logic means that the thread_local impl from the real std is used, so the one from the test crate should not matter.

Maybe we should stop using this hack and implement support for this magic linker section instead. I just don't know if there's a good way to ask the compiler for "all static in a particular link_section across all crates".

@RalfJung
Copy link
Member Author

RalfJung commented Apr 7, 2024

I tried to figure out how TLS is currently implemented on Windows, but I got lost in the dark forest that is std::sys.^^ I can't figure out where this call (imp::create) would go on Windows; nothing in the Windows folder declares a create function.

EDIT: Oh, looks like sys_common::thread_local_key is Unix-only. I got fooled by the "common" in the name and it not being in pal.

@ChrisDenton
Copy link
Contributor

The Windows specific bits happen here: https://github.com/rust-lang/rust/blob/e43aef0ef9cc9d2d12c138b36fd817f7c41d0152/library/std/src/sys/pal/windows/thread_local_key.rs

Note though that the StaticKey (and related) bits aren't actually used if #[cfg(target_thread_local)].

@RalfJung
Copy link
Member Author

RalfJung commented Apr 7, 2024

The bug was reported on i686-pc-windows-gnu. Not sure if that's currently target_thread_local or not... I think it is? Only the 32bit MSVC target is not? But I keep forgetting which one exactly it is so I may be wrong.

@RalfJung
Copy link
Member Author

RalfJung commented Apr 7, 2024

However I think even with target_thread_local, dtors are handled the same way -- via thread::local_impl::Key::<T>::register_dtor.

@ChrisDenton
Copy link
Contributor

32-bit msvc is currently not target_thread_local. However, that may change soon.

register_keyless_dtor is used when target_thread_local is enabled, otherwise register_dtor is used. Both ultimately use the special .CRT$XLB linker magic.

@RalfJung
Copy link
Member Author

RalfJung commented Apr 7, 2024

Ah, register_dtor is actually register_keyless_dtor.

pub use super::thread_local_key::register_keyless_dtor as register_dtor;

This is such a maze...^^

@ChrisDenton
Copy link
Contributor

You're not the first to notice that: #110897

@Nilstrieb Nilstrieb added O-windows Operating system: Windows A-thread-locals Area: Thread local storage (TLS) C-bug Category: This is a bug. A-miri Area: The miri tool and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Apr 7, 2024
@RalfJung RalfJung changed the title Miri sometimes reports memory leak in reentrant lock on Windows Miri sometimes reports memory leak in thread-local storage on Windows Apr 15, 2024
@mati865
Copy link
Contributor

mati865 commented Apr 15, 2024

The bug was reported on i686-pc-windows-gnu. Not sure if that's currently target_thread_local or not... I think it is? Only the 32bit MSVC target is not? But I keep forgetting which one exactly it is so I may be wrong.

All tier 1 windows-gnu targets have target_thread_local disabled.
There are similar tier 2 targets windows-gnullvm which have working TLS and have target_thread_local enabled.

@RalfJung
Copy link
Member Author

Okay, thanks for clarifying.

Is there an issue tracking why the windows-gnu targets can't use target_thread_local?

@bors bors closed this as completed in 0230848 Apr 15, 2024
@mati865
Copy link
Contributor

mati865 commented Apr 15, 2024

Some of binaries produced by tests inside ui/ crash with some code that I can'it recall 😉
That could be discrepancy between our default LLVM backend which uses Windows native TLS and GNU tools which use emuTLS but I didn't dedicated enough time to it and I'm not planning currently.

@joboet
Copy link
Contributor

joboet commented Apr 15, 2024

I tried enabling native TLS in #102243, the result being access violations when running rustc. Things may have changed since then, though.

@mati865
Copy link
Contributor

mati865 commented Apr 15, 2024

I've tried it multiple times over the years and the result was always the same, this time it could work if emutls is enabled as well: #117873 but I don't have high hopes here and I think it'd still require some fixes.

EDIT: As I anticipated it needs more work:

Details
$ ./x.py t tests/ui
...
failures:

---- [ui] tests\ui\extern\issue-64655-extern-rust-must-allow-unwind.rs#fat0 stdout ----

error in revision `fat0`: test compilation failed although it shouldn't!
status: exit code: 1
command: PATH="H:\projects\rust\build\x86_64-pc-windows-gnu\stage1\bin;H:\projects\rust\build\x86_64-pc-windows-gnu\stage0-bootstrap-tools\x86_64-pc-windows-gnu\release\deps;H:\projects\rust\build\x86_64-pc-windows-gnu\stage0\bin;C:\Users\mateusz\bin;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\local\bin;C:\Program Files\Git\usr\bin;C:\Program Files\Git\usr\bin;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\bin;C:\Users\mateusz\bin;C:\Program Files\Alacritty;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\libnvvp;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Windows\System32\OpenSSH;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\dotnet;C:\Program Files\NVIDIA Corporation\Nsight Compute 2023.1.1;C:\Program Files\WezTerm;C:\Program Files\Intel\PresentMon\PresentMonApplication;C:\Program Files\NVIDIA Corporation\NVIDIA App\NvDLISR;C:\Program Files\Git\cmd;C:\Users\mateusz\.cargo\bin;C:\Users\mateusz\AppData\Local\Microsoft\WindowsApps;C:\Users\mateusz\AppData\Local\JetBrains\Toolbox\scripts;C:\Users\mateusz\AppData\Local\GitHubDesktop\bin;C:\Users\mateusz\AppData\Local\Programs\Microsoft VS Code\bin;D:\msys64\mingw64\bin;C:\Program Files\Git\usr\bin\vendor_perl;C:\Program Files\Git\usr\bin\core_perl" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1\\bin\\rustc.exe" "H:\\projects\\rust\\tests\\ui\\extern\\issue-64655-extern-rust-must-allow-unwind.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=C:\\Users\\mateusz\\.cargo" "--sysroot" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1" "--target=x86_64-pc-windows-gnu" "--cfg" "fat0" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "-o" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\test\\ui\\extern\\issue-64655-extern-rust-must-allow-unwind.fat0\\a.exe" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\native\\rust-test-helpers" "-Clinker=d:/msys64/mingw64/bin/gcc.exe" "-L" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\test\\ui\\extern\\issue-64655-extern-rust-must-allow-unwind.fat0\\auxiliary" "-C" "opt-level=0" "-C" "lto=fat"
stdout: none
--- stderr -------------------------------
error: linking with `d:/msys64/mingw64/bin/gcc.exe` failed: exit code: 1
   |
   = note: "d:/msys64/mingw64/bin/gcc.exe" "-fno-use-linker-plugin" "-Wl,--dynamicbase" "-Wl,--disable-auto-image-base" "-m64" "-Wl,--high-entropy-va" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\rsbegin.o" "C:\\Users\\mateusz\\AppData\\Local\\Temp\\rustceEqcfE\\symbols.o" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\test\\ui\\extern\\issue-64655-extern-rust-must-allow-unwind.fat0\\a.issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0.rcgu.o" "-L" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\native\\rust-test-helpers" "-L" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\test\\ui\\extern\\issue-64655-extern-rust-must-allow-unwind.fat0\\auxiliary" "-L" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib" "-Wl,-Bstatic" "C:\\Users\\mateusz\\AppData\\Local\\Temp\\rustceEqcfE\\libstd-418d4ec99f519a29.rlib" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libcompiler_builtins-4d92a5d2ada47422.rlib" "-Wl,-Bdynamic" "-lkernel32" "-ladvapi32" "-lkernel32" "-lntdll" "-luserenv" "-lws2_32" "-lsynchronization" "-lkernel32" "-lws2_32" "-lkernel32" "-lntdll" "-lkernel32" "-lgcc_eh" "-l:libpthread.a" "-lmsvcrt" "-lmingwex" "-lmingw32" "-lgcc" "-lmsvcrt" "-lmingwex" "-luser32" "-lkernel32" "-Wl,--nxcompat" "-L" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib" "-o" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\test\\ui\\extern\\issue-64655-extern-rust-must-allow-unwind.fat0\\a.exe" "-Wl,--gc-sections" "-no-pie" "-Wl,--strip-debug" "-nodefaultlibs" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\rsend.o"
   = note: D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\extern\issue-64655-extern-rust-must-allow-unwind.fat0\a.issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0.rcgu.o:issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0:(.data+0x718): undefined reference to `std::sys_common::thread_info::THREAD_INFO::__getit::VAL'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\extern\issue-64655-extern-rust-must-allow-unwind.fat0\a.issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0.rcgu.o:issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0:(.data+0x720): undefined reference to `std::sys_common::thread_info::THREAD_INFO::__getit::STATE'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\extern\issue-64655-extern-rust-must-allow-unwind.fat0\a.issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0.rcgu.o:issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0:(.data+0x728): undefined reference to `std::sync::reentrant_lock::current_thread_unique_ptr::X::__getit::VAL'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\extern\issue-64655-extern-rust-must-allow-unwind.fat0\a.issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0.rcgu.o:issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0:(.data+0x730): undefined reference to `std::panicking::panic_count::LOCAL_PANIC_COUNT::__getit::VAL'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\extern\issue-64655-extern-rust-must-allow-unwind.fat0\a.issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0.rcgu.o:issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0:(.data+0xa28): undefined reference to `std::io::stdio::OUTPUT_CAPTURE::__getit::__KEY'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\extern\issue-64655-extern-rust-must-allow-unwind.fat0\a.issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0.rcgu.o:issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0:(.data+0xb30): undefined reference to `std::sys::pal::windows::thread_local_key::DESTRUCTORS'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\extern\issue-64655-extern-rust-must-allow-unwind.fat0\a.issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0.rcgu.o:issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0:(.data+0xc28): undefined reference to `std::hash::random::RandomState::new::KEYS::__getit::__KEY'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\extern\issue-64655-extern-rust-must-allow-unwind.fat0\a.issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0.rcgu.o:issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0:(.data+0xc30): undefined reference to `std::sync::mpmc::context::Context::with::CONTEXT::__getit::__KEY'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\extern\issue-64655-extern-rust-must-allow-unwind.fat0\a.issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0.rcgu.o:issue_64655_extern_rust_must_allow_unwind.56e668df17fe0d16-cgu.0:(.data+0xdb0): undefined reference to `std::sync::mpmc::waker::current_thread_id::DUMMY::__getit::__KEY'
           collect2.exe: error: ld returned 1 exit status

   = note: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
   = note: use the `-l` flag to specify native libraries to link

error: aborting due to 1 previous error
------------------------------------------


---- [ui] tests\ui\issues\issue-44056.rs stdout ----

error: test compilation failed although it shouldn't!
status: exit code: 1
command: PATH="H:\projects\rust\build\x86_64-pc-windows-gnu\stage1\bin;H:\projects\rust\build\x86_64-pc-windows-gnu\stage0-bootstrap-tools\x86_64-pc-windows-gnu\release\deps;H:\projects\rust\build\x86_64-pc-windows-gnu\stage0\bin;C:\Users\mateusz\bin;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\local\bin;C:\Program Files\Git\usr\bin;C:\Program Files\Git\usr\bin;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\bin;C:\Users\mateusz\bin;C:\Program Files\Alacritty;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.1\libnvvp;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Windows\System32\OpenSSH;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\dotnet;C:\Program Files\NVIDIA Corporation\Nsight Compute 2023.1.1;C:\Program Files\WezTerm;C:\Program Files\Intel\PresentMon\PresentMonApplication;C:\Program Files\NVIDIA Corporation\NVIDIA App\NvDLISR;C:\Program Files\Git\cmd;C:\Users\mateusz\.cargo\bin;C:\Users\mateusz\AppData\Local\Microsoft\WindowsApps;C:\Users\mateusz\AppData\Local\JetBrains\Toolbox\scripts;C:\Users\mateusz\AppData\Local\GitHubDesktop\bin;C:\Users\mateusz\AppData\Local\Programs\Microsoft VS Code\bin;D:\msys64\mingw64\bin;C:\Program Files\Git\usr\bin\vendor_perl;C:\Program Files\Git\usr\bin\core_perl" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1\\bin\\rustc.exe" "H:\\projects\\rust\\tests\\ui\\issues\\issue-44056.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=C:\\Users\\mateusz\\.cargo" "--sysroot" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1" "--target=x86_64-pc-windows-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--out-dir" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\test\\ui\\issues\\issue-44056" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\native\\rust-test-helpers" "-Clinker=d:/msys64/mingw64/bin/gcc.exe" "-L" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\test\\ui\\issues\\issue-44056\\auxiliary" "-Ctarget-feature=+avx" "-Clto"
stdout: none
--- stderr -------------------------------
error: linking with `d:/msys64/mingw64/bin/gcc.exe` failed: exit code: 1
   |
   = note: "d:/msys64/mingw64/bin/gcc.exe" "-fno-use-linker-plugin" "-Wl,--dynamicbase" "-Wl,--disable-auto-image-base" "-m64" "-Wl,--high-entropy-va" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\rsbegin.o" "C:\\Users\\mateusz\\AppData\\Local\\Temp\\rustcz2km9U\\symbols.o" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\test\\ui\\issues\\issue-44056\\issue-44056.issue_44056.fdfc3584e7394587-cgu.0.rcgu.o" "-L" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\native\\rust-test-helpers" "-L" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\test\\ui\\issues\\issue-44056\\auxiliary" "-L" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib" "-Wl,-Bstatic" "C:\\Users\\mateusz\\AppData\\Local\\Temp\\rustcz2km9U\\libstd-418d4ec99f519a29.rlib" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\libcompiler_builtins-4d92a5d2ada47422.rlib" "-Wl,-Bdynamic" "-lkernel32" "-ladvapi32" "-lkernel32" "-lntdll" "-luserenv" "-lws2_32" "-lsynchronization" "-lkernel32" "-lws2_32" "-lkernel32" "-lntdll" "-lkernel32" "-lgcc_eh" "-l:libpthread.a" "-lmsvcrt" "-lmingwex" "-lmingw32" "-lgcc" "-lmsvcrt" "-lmingwex" "-luser32" "-lkernel32" "-Wl,--nxcompat" "-L" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib" "-o" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\test\\ui\\issues\\issue-44056\\issue-44056.exe" "-Wl,--gc-sections" "-no-pie" "-Wl,--strip-debug" "-nodefaultlibs" "H:\\projects\\rust\\build\\x86_64-pc-windows-gnu\\stage1\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\rsend.o"
   = note: D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\issues\issue-44056\issue-44056.issue_44056.fdfc3584e7394587-cgu.0.rcgu.o:issue_44056.fdfc3584e7394587-cgu.0:(.data+0x718): undefined reference to `std::sys_common::thread_info::THREAD_INFO::__getit::VAL'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\issues\issue-44056\issue-44056.issue_44056.fdfc3584e7394587-cgu.0.rcgu.o:issue_44056.fdfc3584e7394587-cgu.0:(.data+0x720): undefined reference to `std::sys_common::thread_info::THREAD_INFO::__getit::STATE'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\issues\issue-44056\issue-44056.issue_44056.fdfc3584e7394587-cgu.0.rcgu.o:issue_44056.fdfc3584e7394587-cgu.0:(.data+0x728): undefined reference to `std::sync::reentrant_lock::current_thread_unique_ptr::X::__getit::VAL'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\issues\issue-44056\issue-44056.issue_44056.fdfc3584e7394587-cgu.0.rcgu.o:issue_44056.fdfc3584e7394587-cgu.0:(.data+0x730): undefined reference to `std::panicking::panic_count::LOCAL_PANIC_COUNT::__getit::VAL'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\issues\issue-44056\issue-44056.issue_44056.fdfc3584e7394587-cgu.0.rcgu.o:issue_44056.fdfc3584e7394587-cgu.0:(.data+0xa28): undefined reference to `std::io::stdio::OUTPUT_CAPTURE::__getit::__KEY'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\issues\issue-44056\issue-44056.issue_44056.fdfc3584e7394587-cgu.0.rcgu.o:issue_44056.fdfc3584e7394587-cgu.0:(.data+0xb30): undefined reference to `std::sys::pal::windows::thread_local_key::DESTRUCTORS'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\issues\issue-44056\issue-44056.issue_44056.fdfc3584e7394587-cgu.0.rcgu.o:issue_44056.fdfc3584e7394587-cgu.0:(.data+0xc28): undefined reference to `std::hash::random::RandomState::new::KEYS::__getit::__KEY'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\issues\issue-44056\issue-44056.issue_44056.fdfc3584e7394587-cgu.0.rcgu.o:issue_44056.fdfc3584e7394587-cgu.0:(.data+0xc30): undefined reference to `std::sync::mpmc::context::Context::with::CONTEXT::__getit::__KEY'
           D:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: H:\projects\rust\build\x86_64-pc-windows-gnu\test\ui\issues\issue-44056\issue-44056.issue_44056.fdfc3584e7394587-cgu.0.rcgu.o:issue_44056.fdfc3584e7394587-cgu.0:(.data+0xdb0): undefined reference to `std::sync::mpmc::waker::current_thread_id::DUMMY::__getit::__KEY'
           collect2.exe: error: ld returned 1 exit status

   = note: some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
   = note: use the `-l` flag to specify native libraries to link

error: aborting due to 1 previous error
------------------------------------------



failures:
    [ui] tests\ui\extern\issue-64655-extern-rust-must-allow-unwind.rs#fat0
    [ui] tests\ui\issues\issue-44056.rs
$ git diff
diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs
index 25f02dc1451..3b2d174071a 100644
--- a/compiler/rustc_target/src/spec/base/windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::LinkSelfContainedDefault;
+use crate::spec::{LinkSelfContainedDefault, TlsModel};
 use crate::spec::{add_link_args, crt_objects};
 use crate::spec::{cvs, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions};
 use std::borrow::Cow;
@@ -40,6 +40,7 @@ pub fn opts() -> TargetOptions {
         //
         // See https://github.com/rust-lang/rust/pull/47483 for some more details.
         "-lmsvcrt",
+        "-lmingwex", // This one is required for newer mingw-w64 versions
         "-luser32",
         "-lkernel32",
     ];
@@ -103,6 +104,8 @@ pub fn opts() -> TargetOptions {
         // output DWO, despite using DWARF, doesn't use ELF..
         debuginfo_kind: DebuginfoKind::Pdb,
         supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
+        has_thread_local: true,
+        tls_model: TlsModel::Emulated,
         ..Default::default()
     }
 }

github-actions bot pushed a commit to rust-lang/miri that referenced this issue Apr 16, 2024
Miri on Windows: run .CRT$XLB linker section on thread-end

Hopefully fixes rust-lang/rust#123583

First commit is originally by `@bjorn3`

r? `@oli-obk`
Cc `@ChrisDenton`
@matthiaskrgr matthiaskrgr reopened this Apr 22, 2024
@matthiaskrgr
Copy link
Member

@RalfJung RalfJung changed the title Miri sometimes reports memory leak in thread-local storage on Windows Miri sometimes reports memory leak in thread-local storage on i686-pc-windows-gnu Apr 22, 2024
@RalfJung
Copy link
Member Author

So, it was not some issue with the global destructor after all. And it seems to always hit only the reentrant lock, even though that is not the only thread-local we have.

Maybe there's an actual race condition leading to occasional memory leaks here?

@RalfJung RalfJung changed the title Miri sometimes reports memory leak in thread-local storage on i686-pc-windows-gnu Miri sometimes reports memory leak in thread-local storage on *-pc-windows-gnu Apr 22, 2024
@RalfJung
Copy link
Member Author

RalfJung commented Apr 22, 2024

Minimal reproducer so far:

use std::thread;

pub(crate) fn current_thread_unique_ptr() {
    thread_local! { static X: u8 = const { 0 } }
    X.with(|_x| {})
}

fn main() {
    let j2 = thread::spawn(current_thread_unique_ptr);
    current_thread_unique_ptr();
    j2.join().unwrap();
}

The leak only occurs on the windows-gnu targets.

@ChrisDenton
Copy link
Contributor

Presumably this is due to the TLS dtor when not has_thread_local.

All the msvc targets currently use the #[cfg(target_thread_local)] code.

@RalfJung
Copy link
Member Author

Meanwhile, #124270 should work around the CI issue.

@RalfJung
Copy link
Member Author

FWIW the issue reproduces with and without const { ... }.

@RalfJung

This comment was marked as resolved.

@RalfJung
Copy link
Member Author

Oh never mind, I copied the span from the closure not the stacktrace.^^

It's this Box:

let ptr = Box::into_raw(Box::new(Value { inner: LazyKeyInner::new(), key: self }));

@RalfJung
Copy link
Member Author

One key ingredient to the leak seems to be not loading the latest value here:

let mut cur = DTORS.load(Acquire);

Cc @joboet

bors added a commit to rust-lang-ci/rust that referenced this issue Apr 22, 2024
miri libstd tests: test windows-msvc instead of windows-gnu

This avoids rust-lang#123583. MSVC is the more widely used target anyway AFAIK, so probably makes more sense to cover that.
@RalfJung
Copy link
Member Author

Ah, I think I got it. :)
#124281

@bors bors closed this as completed in 4eda876 Apr 24, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Apr 24, 2024
Rollup merge of rust-lang#124281 - RalfJung:win-tls, r=joboet

fix weak memory bug in TLS on Windows

We need to store the `key` *after* we register the dtor.

Now I hope there isn't also some other reason why we have to actually register the dtor last... `@joboet` is there a reason you picked this particular order in rust-lang#102655?

Fixes rust-lang#123583
@matthiaskrgr
Copy link
Member

🏅

github-actions bot pushed a commit to rust-lang/miri that referenced this issue Apr 25, 2024
fix weak memory bug in TLS on Windows

We need to store the `key` *after* we register the dtor.

Now I hope there isn't also some other reason why we have to actually register the dtor last... `@joboet` is there a reason you picked this particular order in rust-lang/rust#102655?

Fixes rust-lang/rust#123583
bors added a commit to rust-lang/miri that referenced this issue Apr 25, 2024
add a test for the TLS memory leak

This is a regression test for rust-lang/rust#123583.
RalfJung pushed a commit to RalfJung/rust that referenced this issue Apr 25, 2024
add a test for the TLS memory leak

This is a regression test for rust-lang#123583.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-miri Area: The miri tool A-thread-locals Area: Thread local storage (TLS) C-bug Category: This is a bug. O-windows Operating system: Windows
Projects
None yet
7 participants