Print statement banishes memory leak?

Hi all,

I'm writing a data structure, which I know is leaky according to Miri output. For example, this code:

fn main() {
    let sv = SecVec::<isize>::new();
    for i in 0..10 {
        sv.push(1);
    }
}

produces the following Miri output:

The following memory was leaked: alloc11218 (Rust heap, size: 24, align: 8) {
    0x00 │ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
    0x10 │ ╾0x2b450[a2001]<27385>╼                         │ ╾──────╼
}
alloc11290 (Rust heap, size: 16, align: 8) {
    ╾0x5b5a0[a11218]<untagged> (8 ptr bytes)╼ 05 00 00 00 00 00 00 00 │ ╾──────╼........
}
alloc15276 (Rust heap, size: 24, align: 8) {
    0x00 │ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
    0x10 │ ╾0x2b460[a2001]<37648>╼                         │ ╾──────╼
}
alloc15348 (Rust heap, size: 16, align: 8) {
    ╾0x6f2d0[a15276]<untagged> (8 ptr bytes)╼ 07 00 00 00 00 00 00 00 │ ╾──────╼........
}
alloc16100 (Rust heap, size: 24, align: 8) {
    0x00 │ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
    0x10 │ ╾0x2b460[a2001]<39775>╼                         │ ╾──────╼
}
alloc16172 (Rust heap, size: 16, align: 8) {
    ╾0x73418[a16100]<untagged> (8 ptr bytes)╼ 07 00 00 00 00 00 00 00 │ ╾──────╼........
}

However, when I insert a println!() into the loop, like so:

fn main() {
    let sv = SecVec::<isize>::new();
    for i in 0..10 {
        sv.push(1);
        println!("{i}");
    }
}

Miri doesn't detect any leakage at all!

But when I stop printing the loop variable, just a newline:

fn main() {
    let sv = SecVec::<isize>::new();
    for _ in 0..10 {
        sv.push(1);
        println!();
    }
}

Miri detects some leakage, albeit less:

The following memory was leaked: alloc7147 (Rust heap, size: 24, align: 8) {
    0x00 │ 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
    0x10 │ ╾0x2b438[a2006]<17039>╼                         │ ╾──────╼
}
alloc7219 (Rust heap, size: 16, align: 8) {
    ╾0x48710[a7147]<untagged> (8 ptr bytes)╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
}
alloc2006 (deallocated)

For some reason, the data structure consistently "leaks" less when doing the blank print, and doesn't "leak" when the print uses the loop variable. The data structure never touches the loop variable.

Any ideas on what might be happening? I'm more curious than anything :thinking:

Thank you as always!

2 Likes

Curiosity + 1

1 Like
  • How is your data structure leaking memory?
  • Does it contain any unsafe code? It is possible that you are invoking UB and inadvertently overwriting memory that happens to be used by println!() so it's marked "in use". This is only a wild guess, though.
5 Likes

I'm implementing a compare-and-swap algorithm with is CAS'ing pointers. The pointers can be read from multiple threads, so when I swap out a pointer deallocation is deferred until there are no readers. I'm using haphazard - Rust (docs.rs) to do this.

There is one section where using a reference made miri mad, so I used a raw pointer instead and miri was fine with it (with Zmiri-tag-raw-pointers and without). I'm pretty sure this is the source of the leak. I do dereference the raw pointer, but I've carefully checked it for correctness.

There is unsafe code, but it's pretty minimal and I've basically reduced to only calling functions from haphazard that are unsafe. I've pretty carefully checked over the documentation.