Memory being dropped out of order in 'a

āš“ Rust    šŸ“… 2025-08-06    šŸ‘¤ surdeus    šŸ‘ļø 6      

surdeus

I’m trying to write a type that is sort of like Cow<[X]>. It is called A. A looks like this minimal example:

struct A<'a, X> {
    ptr: NonNull<X>,
    len: usize,
    own: bool,
    _pd: PhantomData<&'a X>,
}

impl<'a, X> A<'a, X> {
    pub fn new(len: usize) -> A<'a, X> {
        let lay = Layout::array::<X>(len).unwrap();
        let ptr = unsafe { alloc::alloc(lay) };
        let ptr = NonNull::new(ptr as *mut X).unwrap();
        A {
            ptr,
            len,
            own: true,
            _pd: PhantomData,
        }
    }

    pub fn set(&mut self, i: usize, x: X) {
        unsafe {
            write(self.ptr.as_ptr().add(i), x);
        }
    }

    pub fn get(&self, i: usize) -> X {
        unsafe { read(self.ptr.as_ptr().add(i)) }
    }

    pub fn as_ref(&self) -> A<'a, X> {
        A {
            ptr: self.ptr,
            len: self.len,
            own: false,
            _pd: PhantomData,
        }
    }
}

impl<'a, X> Drop for A<'a, X> {
    fn drop(&mut self) {
        if self.own {
            unsafe {
                alloc::dealloc(
                    self.ptr.as_ptr() as *mut u8,
                    Layout::array::<X>(self.len).unwrap(),
                );
            }
        }
    }
}

but creating references inline sometimes causes the original A to be dropped before the ref, like this

fn main() {
    let mut a: A<i32> = A::new(3).as_ref();
    a.set(0, 1);
    a.set(1, 2);
    a.set(2, 3);

    for i in 0..3 {
        println!("{i}:\t{}", a.get(i));
    }
}

which yields an error in miri

  --> bin/drop.rs:30:13
   |
30 |             write(self.ptr.as_ptr().add(i), x);
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
   |
   = 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
help: alloc392 was allocated here:
  --> bin/drop.rs:18:28
   |
18 |         let ptr = unsafe { alloc::alloc(lay) };
   |                            ^^^^^^^^^^^^^^^^^
help: alloc392 was deallocated here:
  --> bin/drop.rs:52:17
   |
52 | /                 alloc::dealloc(
53 | |                     self.ptr.as_ptr() as *mut u8,
54 | |                     Layout::array::<X>(self.len).unwrap(),
55 | |                 );
   | |_________________^
   = note: BACKTRACE (of the first span):
   = note: inside `A::<'_, i32>::set` at bin/drop.rs:30:13: 30:47
note: inside `main`
  --> bin/drop.rs:63:5
   |
63 |     a.set(0, 1);
   |     ^^^^^^^^^^^

does anyone know what im doing wrong here?

1 post - 1 participant

Read full topic

šŸ·ļø Rust_feed