Home > Enterprise >  Pointer to first element of vector in Result<Vec<f64>, _> is corrupted
Pointer to first element of vector in Result<Vec<f64>, _> is corrupted

Time:12-23

I have a Result<Vec<f64>, _>. When I try to extract a pointer to the actual f64 array, what I observe is that the array dptr points to is a corrupted version of the expected array (the first 10 bytes have been changed).

Why does this happen, and how I can avoid it?

use std::error::Error;

fn main() {
    let res: Result<Vec<f64>, Box<dyn Error>> = Ok(vec![1., 2., 3., 4.]);
    let dptr: *const f64 = match res {
        Ok(v) => &v[0], 
        Err(_) => std::ptr::null(),
    };
    assert_eq!(unsafe { *dptr }, 1.0);
}

Result:

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `0.0`,
 right: `1.0`', src/main.rs:9:5

Playground

CodePudding user response:

The behaviour of that program is undefined, which can be seen by running it under Miri, which is a Rust interpreter that can sometimes detect Undefined Behavior. (you can do this in the playground by clicking "Tools" (top right) -> "Miri"):

error: Undefined Behavior: pointer to alloc1039 was dereferenced after this allocation got freed
 --> src/main.rs:9:25
  |
9 |     assert_eq!(unsafe { *dptr }, 1.0);
  |                         ^^^^^ pointer to alloc1039 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

What's happening here is a use-after-free: the Ok(v) => &v[0], line moves data from v (and thus res), causing it to be freed. Later, data used for other variable overwrote the existing data (because using a pointer after the memory it points to is freed is Undefined Behaviour).

If you had tried to read the data out of the res the normal way without unsafe, you would have got a compile-time error for this very issue:

error[E0382]: use of partially moved value: `res`
 --> src/main.rs:9:10
  |
6 |         Ok(v) => &v[0],
  |            - value partially moved here
...
9 |     dbg!(res.unwrap()[0]);
  |          ^^^ value used here after partial move
  |
  = note: partial move occurs because value has type `Vec<f64>`, which does not implement the `Copy` trait
help: borrow this field in the pattern to avoid moving `res.0`
  |
6 |         Ok(ref v) => &v[0],
  |               

(playground)

  • Related