Search code examples
linuxmemory-leaksrustvalgrind

Why does Valgrind show no allocations for a Rust program?


I'm learning Rust and I was playing with Box, so I tried checking leaks with valgrind but it shows that there are no allocations on the heap:

$ rustc -C opt-level=0 raii.rs
$ valgrind ./raii
==3850== Memcheck, a memory error detector
==3850== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==3850== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==3850== Command: ./raii
==3850== 
5
Changed:10
==3850== 
==3850== HEAP SUMMARY:
==3850==     in use at exit: 0 bytes in 0 blocks
==3850==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==3850== 
==3850== All heap blocks were freed -- no leaks are possible
==3850== 
==3850== For counts of detected and suppressed errors, rerun with: -v
==3850== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

valgrind --leak-check=full ./raii shows exaclty the same result.

Here's the Rust code:

fn main() {
    let mut _box2 = Box::new(5i32);

    println!("{}", _box2);
    *_box2 = 10i32;
    println!("Changed:{}", _box2);

    {
        let _box3 = Box::new(4i32);
    }
}

Some other info:

$ rustc -V
rustc 1.8.0 (db2939409 2016-04-11)

$ valgrind --version
valgrind-3.10.1

$ uname -a
Linux 3.19.0-59-generic #65~14.04.1-Ubuntu SMP Tue Apr 19 18:57:09 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

Why is that? I thought Box allocates the variable on the heap. Also, this example shows almost the same code and Valgrind shows allocations there.

If I add the following code:

let _stack = (1u64, 2u64, 3u64);
let _heap = Box::new((4u64, 5u64, 6u64));
println!("Memory used by stack: {} bytes", std::mem::size_of_val(&_stack));
println!("Memory used by heap: {} bytes", std::mem::size_of_val(&_heap));

It prints exactly what I expected:

$ ./raii 
Memory used by stack: 24 bytes
Memory used by heap: 8 bytes
  • In the second case, the tuple was placed on the heap and a pointer (8 bytes) was pushed to the stack.
  • In the first case tuple was placed on the stack, so it takes 24 bytes.

Valgrind seems to be able to count heap allocations from other programs:

$ valgrind echo "test"
==4575== Memcheck, a memory error detector
==4575== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4575== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4575== Command: echo test
==4575== 
test
==4575== 
==4575== HEAP SUMMARY:
==4575==     in use at exit: 0 bytes in 0 blocks
==4575==   total heap usage: 30 allocs, 30 frees, 3,681 bytes allocated
==4575== 
==4575== All heap blocks were freed -- no leaks are possible
==4575== 
==4575== For counts of detected and suppressed errors, rerun with: -v
==4575== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Solution

  • Rust 1.32

    As of Rust 1.32, the default allocator for an executable is now the system allocator, so you don't need to set anything by default.

    Previous versions

    Rust uses jemalloc as the allocator when you build a binary. The way that jemalloc is currently compiled does not contain the Valgrind hooks needed.

    If you need the ability to track allocations with Valgrind, you can switch to the the system allocator if you are using nightly Rust.

    See also: