valgrind shows memory leak for a simple print statement #19776

Open
rjammala opened this Issue Dec 12, 2014 · 18 comments

Projects

None yet

7 participants

@rjammala

Here are the details:
$ valgrind --version
valgrind-3.8.1

rustc --version
rustc 0.13.0-nightly (193390d 2014-12-11 22:56:54 +0000)

uname -a
Linux 2.6.32-504.1.3.el6.x86_64 #1 SMP Tue Nov 11 17:57:25 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

Here is the program:

$ cat learn.rs
fn main() {
println!("Hello World!")
println!("How are you today")
}

$ valgrind --leak-check=full ./learn
==38235== Memcheck, a memory error detector
==38235== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==38235== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==38235== Command: ./learn
==38235==

Hello World!
How are you today
==38235==
==38235== HEAP SUMMARY:
==38235== in use at exit: 1,184 bytes in 4 blocks
==38235== total heap usage: 18 allocs, 14 frees, 2,696 bytes allocated
==38235==
==38235== LEAK SUMMARY:
==38235== definitely lost: 0 bytes in 0 blocks
==38235== indirectly lost: 0 bytes in 0 blocks
==38235== possibly lost: 0 bytes in 0 blocks
==38235== still reachable: 1,184 bytes in 4 blocks
==38235== suppressed: 0 bytes in 0 blocks
==38235== Reachable blocks (those to which a pointer was found) are not shown.
==38235== To see them, rerun with: --leak-check=full --show-reachable=yes
==38235==
==38235== For counts of detected and suppressed errors, rerun with: -v
==38235== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)

@alexcrichton
Member

Can you run with --leak-check=full and --show-reachable=yes and paste the output here as well? I sadly can't reproduce this locally :(

@rjammala
$ valgrind --leak-check=full --show-reachable=yes ./learn
==3771== Memcheck, a memory error detector
==3771== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==3771== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==3771== Command: ./learn
==3771== 
Hello World!
How are you today
==3771== 
==3771== HEAP SUMMARY:
==3771==     in use at exit: 1,184 bytes in 4 blocks
==3771==   total heap usage: 18 allocs, 14 frees, 2,696 bytes allocated
==3771== 
==3771== 32 bytes in 1 blocks are still reachable in loss record 1 of 4
==3771==    at 0x128A12: je_mallocx (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x11137F: thread_local::imp::register_dtor::h6d14515a39f84cf203b (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x1129E3: thread_local::Key$LT$T$GT$::with::h7241079596358413660 (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x112C42: io::stdio::with_task_stdout::hafb602ec3975fdc5syg (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x115557: io::stdio::println_args::h7f0794513d4f2dfcxDg (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x1110B7: main::hbd01322dca53aee9eaa (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x11A22A: rt::start::closure.32122 (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x124FEB: rust_try_inner (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x124FD5: rust_try (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x123BB2: unwind::try::hf2f7fcf7ecc46c43Tyc (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x123A8B: task::Task::run::h911f3b3bbb0c433efKb (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x11A05B: rt::start::hfd264fa826df3608S9x (in /home/rjammalamadaka/Programs/Rust/learn)
==3771== 
==3771== 64 bytes in 1 blocks are still reachable in loss record 2 of 4
==3771==    at 0x128A12: je_mallocx (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x111431: thread_local::imp::register_dtor::h6d14515a39f84cf203b (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x1129E3: thread_local::Key$LT$T$GT$::with::h7241079596358413660 (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x112C42: io::stdio::with_task_stdout::hafb602ec3975fdc5syg (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x115557: io::stdio::println_args::h7f0794513d4f2dfcxDg (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x1110B7: main::hbd01322dca53aee9eaa (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x11A22A: rt::start::closure.32122 (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x124FEB: rust_try_inner (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x124FD5: rust_try (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x123BB2: unwind::try::hf2f7fcf7ecc46c43Tyc (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x123A8B: task::Task::run::h911f3b3bbb0c433efKb (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x11A05B: rt::start::hfd264fa826df3608S9x (in /home/rjammalamadaka/Programs/Rust/learn)
==3771== 
==3771== 64 bytes in 1 blocks are still reachable in loss record 3 of 4
==3771==    at 0x128A12: je_mallocx (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x112CDD: io::stdio::with_task_stdout::hafb602ec3975fdc5syg (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x115557: io::stdio::println_args::h7f0794513d4f2dfcxDg (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x1110B7: main::hbd01322dca53aee9eaa (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x11A22A: rt::start::closure.32122 (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x124FEB: rust_try_inner (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x124FD5: rust_try (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x123BB2: unwind::try::hf2f7fcf7ecc46c43Tyc (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x123A8B: task::Task::run::h911f3b3bbb0c433efKb (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x11A05B: rt::start::hfd264fa826df3608S9x (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x119E35: rt::lang_start::hde2a214462357c7eb9x (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x11117E: main (in /home/rjammalamadaka/Programs/Rust/learn)
==3771== 
==3771== 1,024 bytes in 1 blocks are still reachable in loss record 4 of 4
==3771==    at 0x128A12: je_mallocx (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x112222: io::buffered::BufferedWriter$LT$W$GT$::with_capacity::h8206835914802320726 (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x112D63: io::stdio::with_task_stdout::hafb602ec3975fdc5syg (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x115557: io::stdio::println_args::h7f0794513d4f2dfcxDg (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x1110B7: main::hbd01322dca53aee9eaa (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x11A22A: rt::start::closure.32122 (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x124FEB: rust_try_inner (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x124FD5: rust_try (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x123BB2: unwind::try::hf2f7fcf7ecc46c43Tyc (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x123A8B: task::Task::run::h911f3b3bbb0c433efKb (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x11A05B: rt::start::hfd264fa826df3608S9x (in /home/rjammalamadaka/Programs/Rust/learn)
==3771==    by 0x119E35: rt::lang_start::hde2a214462357c7eb9x (in /home/rjammalamadaka/Programs/Rust/learn)
==3771== 
==3771== LEAK SUMMARY:
==3771==    definitely lost: 0 bytes in 0 blocks
==3771==    indirectly lost: 0 bytes in 0 blocks
==3771==      possibly lost: 0 bytes in 0 blocks
==3771==    still reachable: 1,184 bytes in 4 blocks
==3771==         suppressed: 0 bytes in 0 blocks
==3771== 
==3771== For counts of detected and suppressed errors, rerun with: -v
==3771== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
@alexcrichton
Member

Interesting! It looks like destructors registered with pthread_key_create do not run when the process exits, causing this leak.

@rjammala

Let me know if you need any more information.

@huonw
Member
huonw commented Jul 22, 2015

This seems to be resolved, at least the program with println!s has nothing still reachable.

@alexcrichton
Member

@huonw did you test on linux? You may have been using the ELF TLS instead of pthread tls. I just built a compiler with --disable-elf-tls and it looks like the leak is still present:

$ valgrind ./foo 
==21255== Memcheck, a memory error detector
==21255== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==21255== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==21255== Command: ./foo
==21255== 
Hello World!
How are you today
==21255== 
==21255== HEAP SUMMARY:
==21255==     in use at exit: 312 bytes in 7 blocks
==21255==   total heap usage: 26 allocs, 19 frees, 2,720 bytes allocated
==21255== 
==21255== LEAK SUMMARY:
==21255==    definitely lost: 0 bytes in 0 blocks
==21255==    indirectly lost: 0 bytes in 0 blocks
==21255==      possibly lost: 0 bytes in 0 blocks
==21255==    still reachable: 312 bytes in 7 blocks
==21255==         suppressed: 0 bytes in 0 blocks
==21255== Rerun with --leak-check=full to see details of leaked memory
==21255== 
==21255== For counts of detected and suppressed errors, rerun with: -v
==21255== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
@huonw
Member
huonw commented Jul 22, 2015

Ah, yes, that looks like the difference.

@rjammala

It looks like this is no longer an issue (at least using nightly build of rust (1.7-0-nightly):

]$ valgrind ./learn
==79754== Memcheck, a memory error detector
==79754== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==79754== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==79754== Command: ./learn
==79754==
Hello World!
How are you today
==79754==
==79754== HEAP SUMMARY:
==79754== in use at exit: 0 bytes in 0 blocks
==79754== total heap usage: 4 allocs, 4 frees, 960 bytes allocated
==79754==
==79754== All heap blocks were freed -- no leaks are possible
==79754==
==79754== For counts of detected and suppressed errors, rerun with: -v
==79754== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
[rjammalamadaka@localhost Rust]$ rustc --version
rustc 1.7.0-nightly (81ae8be 2015-12-09)
[rjammalamadaka@localhost Rust]$

@tamird
Contributor
tamird commented Dec 10, 2015

This is probably OK to close then

@alexcrichton
Member

Ah unfortunately as I mentioned earlier this is specifically related to pthread TLS instead of ELF TLS (e.g. really old TLS). I just verified that this is indeed still an issue.

@steveklabnik
Contributor

Trying this today:

$ ./configure --disable-elf-tls
$ make -j6
$ ./x86_64-unknown-linux-gnu/stage2/bin/rustc learn.rs 
$  valgrind --leak-check=full ./learn
==14462== Memcheck, a memory error detector
==14462== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==14462== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==14462== Command: ./learn
==14462== 
Hello World!
How are you today
==14462== 
==14462== HEAP SUMMARY:
==14462==     in use at exit: 0 bytes in 0 blocks
==14462==   total heap usage: 22 allocs, 22 frees, 2,680 bytes allocated
==14462== 
==14462== All heap blocks were freed -- no leaks are possible
==14462== 
==14462== For counts of detected and suppressed errors, rerun with: -v
==14462== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
$ ./x86_64-unknown-linux-gnu/stage2/bin/rustc --version
rustc 1.10.0-dev (80bff1eea 2016-04-26)

Has this been randomly fixed?

@rjammala

yup, even I disabled elf-tls and it seems to have been fixed.
./configure --disable-elf-tls
$ ./x86_64-unknown-linux-gnu/stage2/bin/rustc --version
rustc 1.10.0-dev (80bff1e 2016-04-26)

@alexcrichton : Can we close this?

@tamird
Contributor
tamird commented Apr 27, 2016

Probably needs a test to confirm it doesn't regress.

@alexcrichton
Member

No, this is still an issue. The --disable-elf-tls option no longer works (that's a separate issue) and as I mentioned earlier (and earlier) this requires pthread TLS to be used, and by default we use ELF TLS so it's difficult to reproduce.

Running binaries on older systems with a working valgrind should reproduce this.

@steveklabnik
Contributor

Gah! I didn't realize the flag didn't work; I thought I was using pthread TLS.

@tamird
Contributor
tamird commented Apr 27, 2016

@alexcrichton can you cross-link to the --disable-elf-tls issue?

@alexcrichton
Member

that'd be #32047

@jtsiros
jtsiros commented Nov 8, 2016

Not sure if this is was resolved on nightly, but I see a similar issue for a trivial for a simple heap allocation testing using a bunch of Box::new() calls:

valgrind-3.12.0
rustc 1.12.1 (d4f3940 2016-10-19)
Darwin mC02QF11JG8WN 15.6.0 Darwin Kernel Version 15.6.0: Thu Sep 1 15:01:16 PDT 2016; root:xnu-3248.60.11~2/RELEASE_X86_64 x86_64

valgrind --leak-check=full --show-reachable=yes target/debug/sandbox
==55274== Memcheck, a memory error detector
==55274== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==55274== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==55274== Command: target/debug/sandbox
==55274==
==55274==
==55274== HEAP SUMMARY:
==55274==     in use at exit: 23,333 bytes in 187 blocks
==55274==   total heap usage: 275 allocs, 88 frees, 29,733 bytes allocated
==55274==
==55274== 112 bytes in 1 blocks are still reachable in loss record 39 of 64
==55274==    at 0x10005C681: malloc (in /usr/local/Cellar/valgrind/3.12.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==55274==    by 0x10019CD7C: tlv_allocate_and_initialize_for_key (in /usr/lib/system/libdyld.dylib)
==55274==    by 0x10019D52B: tlv_get_addr (in /usr/lib/system/libdyld.dylib)
==55274==    by 0x10000541D: std::sys_common::thread_info::set::h3ee71b197ed00dc8 (in target/debug/sandbox)
==55274==    by 0x100006782: std::rt::lang_start::hca48e539ce72a288 (in target/debug/sandbox)
==55274==    by 0x100001639: main (in target/debug/sandbox)
==55274==
==55274== 2,064 bytes in 1 blocks are possibly lost in loss record 61 of 64
==55274==    at 0x10005C942: malloc_zone_malloc (in /usr/local/Cellar/valgrind/3.12.0/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==55274==    by 0x10054EEFD: _objc_copyClassNamesForImage (in /usr/lib/libobjc.A.dylib)
==55274==    by 0x100542182: protocols() (in /usr/lib/libobjc.A.dylib)
==55274==    by 0x100542093: readClass(objc_class*, bool, bool) (in /usr/lib/libobjc.A.dylib)
==55274==    by 0x10053FC13: gc_init (in /usr/lib/libobjc.A.dylib)
==55274==    by 0x10054724E: objc_initializeClassPair_internal(objc_class*, char const*, objc_class*, objc_class*) (in /usr/lib/libobjc.A.dylib)
==55274==    by 0x100554132: layout_string_create (in /usr/lib/libobjc.A.dylib)
==55274==    by 0x10054283C: realizeClass(objc_class*) (in /usr/lib/libobjc.A.dylib)
==55274==    by 0x100542300: copySwiftV1MangledName(char const*, bool) (in /usr/lib/libobjc.A.dylib)
==55274==    by 0x1005422E9: copySwiftV1MangledName(char const*, bool) (in /usr/lib/libobjc.A.dylib)
==55274==    by 0x1005422E9: copySwiftV1MangledName(char const*, bool) (in /usr/lib/libobjc.A.dylib)
==55274==    by 0x1005422E9: copySwiftV1MangledName(char const*, bool) (in /usr/lib/libobjc.A.dylib)
==55274==
==55274== LEAK SUMMARY:
==55274==    definitely lost: 0 bytes in 0 blocks
==55274==    indirectly lost: 0 bytes in 0 blocks
==55274==      possibly lost: 2,064 bytes in 1 blocks
==55274==    still reachable: 112 bytes in 1 blocks
==55274==         suppressed: 21,157 bytes in 185 blocks
==55274==
==55274== For counts of detected and suppressed errors, rerun with: -v
==55274== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 15 from 15)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment