Initially I wrote a Heap implementation in Rust, but I was getting strange segfaults, so I narrowed down the code to this example, which reproduces the behavior.
use core::fmt::Debug;
pub struct Node<T: Ord + Debug> {
pub value: *const T,
}
pub struct MaxHeap<T: Ord + Debug> {
pub root: *const Node<T>,
}
impl<T: Ord + Debug> MaxHeap<T> {
pub fn push(&mut self, value: *const T) {
self.root = &mut Node { value: value };
}
}
fn main() {
let a = 124i64;
let b = 124i64;
let c = 1i64;
let mut heap = MaxHeap {
root: &mut Node { value: &a },
};
heap.push(&b);
println!("{:?}", &c);
unsafe {
println!("{:?}", *(*heap.root).value);
}
}
The result I get from this is:
1
Segmentation fault (core dumped)
The interesting thing (to me) is that if I remove the print of c
, there is no segfault and the correct value is printed for the heap root.
124
I expect that anything happening with c
can't affect heap
, but it does. What am I missing?
You've got a use-after-free. In push()
, you assign a temporary to self.root
. The temporary's lifetime is finished of the statement and you're pointing to freed memory. Any further use will cause undefined behavior.
Miri reports it (Tools->Miri in the playground):
error: Undefined Behavior: pointer to alloc1786 was dereferenced after this allocation got freed
--> src/main.rs:29:26
|
29 | println!("{:?}", *(*heap.root).value);
| ^^^^^^^^^^^^^^^^^^^ pointer to alloc1786 was dereferenced after this allocation got freed
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: inside `main` at src/main.rs:29:26
= note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
Since you've got UB, the program can do anything, and any change may affect what it does, even if it seems unrelated.