Closed as duplicate of#135608
Closed as duplicate of#135608
Description
When running cargo test
under valgrind
will full leak check, valgrind shows a memory leak backtrace with "possibly lost" bytes.
This happens with the default template code generated by cargo new
/ cargo init
and affects stable rust versions starting from 1.86.0
. No memory leak is observed with older 1.85.0
.
Repro:
cargo init --lib
echo No memleak with 1.85
valgrind --error-exitcode=42 --tool=memcheck --leak-check=full $(cargo +1.85.0 test --no-run --message-format=json | jq -r 'select(.reason=="compiler-artifact") | .executable | select(. != null)')
echo Memleak with 1.86
valgrind --error-exitcode=42 --tool=memcheck --leak-check=full $(cargo +1.86.0 test --no-run --message-format=json | jq -r 'select(.reason=="compiler-artifact") | .executable | select(. != null)')
echo Memleak with latest nightly
valgrind --error-exitcode=42 --tool=memcheck --leak-check=full $(cargo +nightly test --no-run --message-format=json | jq -r 'select(.reason=="compiler-artifact") | .executable | select(. != null)')
I expected to see this happen: No memory leaks reported.
Instead, this happened: Memory leaks reported for 1.86.0
as well as the latest nightly:
No memleak with 1.85:
Creating library package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Compiling foo v0.1.0 (/tmp/foo)
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.15s
==866796== Memcheck, a memory error detector
==866796== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==866796== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==866796== Command: /tmp/foo/target/debug/deps/foo-60a4b72f22d3bfbc
==866796==
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.07s
==866796==
==866796== HEAP SUMMARY:
==866796== in use at exit: 0 bytes in 0 blocks
==866796== total heap usage: 638 allocs, 638 frees, 77,348 bytes allocated
==866796==
==866796== All heap blocks were freed -- no leaks are possible
==866796==
==866796== For lists of detected and suppressed errors, rerun with: -s
==866796== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Memleak with 1.86:
Memleak with 1.86
Compiling foo v0.1.0 (/tmp/foo)
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.15s
==866870== Memcheck, a memory error detector
==866870== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==866870== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==866870== Command: /tmp/foo/target/debug/deps/foo-c47a447f412d7bfc
==866870==
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.07s
==866870==
==866870== HEAP SUMMARY:
==866870== in use at exit: 48 bytes in 1 blocks
==866870== total heap usage: 639 allocs, 638 frees, 77,374 bytes allocated
==866870==
==866870== 48 bytes in 1 blocks are possibly lost in loss record 1 of 1
==866870== at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==866870== by 0x1830A7: alloc (alloc.rs:96)
==866870== by 0x1830A7: alloc_impl (alloc.rs:192)
==866870== by 0x1830A7: allocate (alloc.rs:254)
==866870== by 0x1830A7: {closure#0}<std::thread::Inner> (sync.rs:484)
==866870== by 0x1830A7: allocate_for_layout<core::mem::maybe_uninit::MaybeUninit<std::thread::Inner>, alloc::sync::{impl#14}::new_uninit::{closure_env#0}<std::thread::Inner>, fn(*mut u8) -> *mut alloc::sync::ArcInner<core::mem::maybe_uninit::MaybeUninit<std::thread::Inner>>> (sync.rs:1952)
==866870== by 0x1830A7: new_uninit<std::thread::Inner> (sync.rs:482)
==866870== by 0x1830A7: std::thread::Thread::new (mod.rs:1429)
==866870== by 0x11B719: std::thread::current::init_current (current.rs:227)
==866870== by 0x11BC53: current_or_unnamed (current.rs:184)
==866870== by 0x11BC53: std::sync::mpmc::context::Context::new (context.rs:72)
==866870== by 0x11A111: __init (context.rs:43)
==866870== by 0x11A111: call_once<fn() -> core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>, ()> (function.rs:250)
==866870== by 0x11A111: unwrap_or_else<core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>, fn() -> core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>> (option.rs:1023)
==866870== by 0x11A111: std::sys::thread_local::native::lazy::Storage<T,D>::initialize (lazy.rs:64)
==866870== by 0x120E05: get_or_init<core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>, (), fn() -> core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>> (lazy.rs:56)
==866870== by 0x120E05: {closure#0} (mod.rs:94)
==866870== by 0x120E05: call_once<std::sync::mpmc::context::{impl#0}::with::CONTEXT::{constant#0}::{closure_env#0}, (core::option::Option<&mut core::option::Option<core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>>>)> (function.rs:250)
==866870== by 0x120E05: try_with<core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>, std::sync::mpmc::context::{impl#0}::with::{closure_env#1}<std::sync::mpmc::list::{impl#3}::recv::{closure_env#1}<test::event::CompletedTest>, ()>, ()> (local.rs:309)
==866870== by 0x120E05: with<std::sync::mpmc::list::{impl#3}::recv::{closure_env#1}<test::event::CompletedTest>, ()> (context.rs:52)
==866870== by 0x120E05: std::sync::mpmc::list::Channel<T>::recv (list.rs:437)
==866870== by 0x13949F: recv_deadline<test::event::CompletedTest> (mod.rs:1119)
==866870== by 0x13949F: recv_timeout<test::event::CompletedTest> (mod.rs:1051)
==866870== by 0x13949F: recv_timeout<test::event::CompletedTest> (mpsc.rs:905)
==866870== by 0x13949F: run_tests<test::console::run_tests_console::{closure_env#2}> (lib.rs:430)
==866870== by 0x13949F: test::console::run_tests_console (console.rs:323)
==866870== by 0x156AD6: test::test_main (lib.rs:150)
==866870== by 0x15745A: test::test_main_static (lib.rs:172)
==866870== by 0x11D8D2: foo::main (lib.rs:0)
==866870== by 0x11D7AA: core::ops::function::FnOnce::call_once (function.rs:250)
==866870== by 0x11DF1D: std::sys::backtrace::__rust_begin_short_backtrace (backtrace.rs:152)
==866870==
==866870== LEAK SUMMARY:
==866870== definitely lost: 0 bytes in 0 blocks
==866870== indirectly lost: 0 bytes in 0 blocks
==866870== possibly lost: 48 bytes in 1 blocks
==866870== still reachable: 0 bytes in 0 blocks
==866870== suppressed: 0 bytes in 0 blocks
==866870==
==866870== For lists of detected and suppressed errors, rerun with: -s
==866870== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Memleak with latest nightly:
Memleak with latest nightly
Compiling foo v0.1.0 (/tmp/foo)
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.10s
==866946== Memcheck, a memory error detector
==866946== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==866946== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==866946== Command: /tmp/foo/target/debug/deps/foo-9e68f113d655f0c4
==866946==
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.07s
==866946==
==866946== HEAP SUMMARY:
==866946== in use at exit: 48 bytes in 1 blocks
==866946== total heap usage: 644 allocs, 643 frees, 77,544 bytes allocated
==866946==
==866946== 48 bytes in 1 blocks are possibly lost in loss record 1 of 1
==866946== at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==866946== by 0x1A6047: alloc (alloc.rs:93)
==866946== by 0x1A6047: alloc_impl (alloc.rs:188)
==866946== by 0x1A6047: allocate (alloc.rs:249)
==866946== by 0x1A6047: {closure#0}<std::thread::Inner> (sync.rs:505)
==866946== by 0x1A6047: allocate_for_layout<core::mem::maybe_uninit::MaybeUninit<std::thread::Inner>, alloc::sync::{impl#14}::new_uninit::{closure_env#0}<std::thread::Inner>, fn(*mut u8) -> *mut alloc::sync::ArcInner<core::mem::maybe_uninit::MaybeUninit<std::thread::Inner>>> (sync.rs:1985)
==866946== by 0x1A6047: new_uninit<std::thread::Inner> (sync.rs:503)
==866946== by 0x1A6047: std::thread::Thread::new (mod.rs:1429)
==866946== by 0x1A5609: std::thread::current::init_current (current.rs:227)
==866946== by 0x1AEA1F: current_or_unnamed (current.rs:184)
==866946== by 0x1AEA1F: std::sync::mpmc::context::Context::new (context.rs:72)
==866946== by 0x141E31: __init (context.rs:43)
==866946== by 0x141E31: call_once<fn() -> core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>, ()> (function.rs:250)
==866946== by 0x141E31: unwrap_or_else<core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>, fn() -> core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>> (option.rs:1048)
==866946== by 0x141E31: std::sys::thread_local::native::lazy::Storage<T,D>::initialize (lazy.rs:64)
==866946== by 0x14348B: get_or_init<core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>, (), fn() -> core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>> (lazy.rs:56)
==866946== by 0x14348B: {closure#0} (mod.rs:94)
==866946== by 0x14348B: call_once<std::sync::mpmc::context::{impl#0}::with::CONTEXT::{constant#0}::{closure_env#0}, (core::option::Option<&mut core::option::Option<core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>>>)> (function.rs:250)
==866946== by 0x14348B: try_with<core::cell::Cell<core::option::Option<std::sync::mpmc::context::Context>>, std::sync::mpmc::context::{impl#0}::with::{closure_env#1}<std::sync::mpmc::list::{impl#3}::recv::{closure_env#1}<test::event::CompletedTest>, ()>, ()> (local.rs:314)
==866946== by 0x14348B: with<std::sync::mpmc::list::{impl#3}::recv::{closure_env#1}<test::event::CompletedTest>, ()> (context.rs:52)
==866946== by 0x14348B: std::sync::mpmc::list::Channel<T>::recv (list.rs:442)
==866946== by 0x15CDF5: recv_deadline<test::event::CompletedTest> (mod.rs:1119)
==866946== by 0x15CDF5: recv_timeout<test::event::CompletedTest> (mod.rs:1051)
==866946== by 0x15CDF5: recv_timeout<test::event::CompletedTest> (mpsc.rs:905)
==866946== by 0x15CDF5: run_tests<test::console::run_tests_console::{closure_env#2}> (lib.rs:441)
==866946== by 0x15CDF5: test::console::run_tests_console (console.rs:323)
==866946== by 0x179CA0: test_main_with_exit_callback<test::test_main::{closure_env#0}> (lib.rs:160)
==866946== by 0x179CA0: test::test_main (lib.rs:101)
==866946== by 0x17A4FA: test::test_main_static (lib.rs:183)
==866946== by 0x13F862: foo::main (lib.rs:0)
==866946== by 0x13F98A: core::ops::function::FnOnce::call_once (function.rs:250)
==866946== by 0x13F80D: std::sys::backtrace::__rust_begin_short_backtrace (backtrace.rs:152)
==866946==
==866946== LEAK SUMMARY:
==866946== definitely lost: 0 bytes in 0 blocks
==866946== indirectly lost: 0 bytes in 0 blocks
==866946== possibly lost: 48 bytes in 1 blocks
==866946== still reachable: 0 bytes in 0 blocks
==866946== suppressed: 0 bytes in 0 blocks
==866946==
==866946== For lists of detected and suppressed errors, rerun with: -s
==866946== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Meta
rustc +1.86.0 --version --verbosee
:
rustc 1.86.0 (05f9846f8 2025-03-31)
binary: rustc
commit-hash: 05f9846f893b09a1be1fc8560e33fc3c815cfecb
commit-date: 2025-03-31
host: x86_64-unknown-linux-gnu
release: 1.86.0
LLVM version: 19.1.7
rustc +nightly --version --verbosee
:
rustc 1.89.0-nightly (d97326eab 2025-05-15)
binary: rustc
commit-hash: d97326eabfc3b2c33abcb08d6bc117aefa697cb7
commit-date: 2025-05-15
host: x86_64-unknown-linux-gnu
release: 1.89.0-nightly
LLVM version: 20.1.4