Anonymous lifetimes in unsafe context

Consider the following code snippet from the xcb crate

#[derive(Copy, Clone)]
pub struct Visualtype {
    data: [u8; 24],
}

pub struct Depth {
    data: [u8],
}

impl Depth {
    // Skipping irrelevant methods

    fn wire_ptr(&self) -> *const u8 { self.data.as_ptr() }

    fn visuals_len(&self) -> u16 {
        unsafe {
            let offset = 2usize;
            let ptr = self.wire_ptr().add(offset) as *const u16;
            *ptr
        }
    }

    pub fn visuals(&self) -> &[Visualtype] {
        unsafe {
            let offset = 8usize;
            let len = (self.visuals_len() as usize) as _;
            let ptr = self.wire_ptr().add(offset) as *const Visualtype;
            std::slice::from_raw_parts(ptr, len)
        }
    }
}

I am trying to understand what's going on in the unsafe block.

  1. Who is the owner of the array of VisualTypes?
  2. Are the VisualTypes being copied or moved? Simply removing the #[derive(copy, clone) does not produce any compilation errors
  3. What is the lifetime of the returned slice ?

Assuming that the unsafe block is sound and I do get a proper &[VisualType] from the visuals method is there anything I can do in safe rust to cause future undefined behavior (i.e is there anything I should be careful of when using the returned type from a function that has an unsafe block ?)

The &[Visualtype] returned from visuals is borrowed from self.

They are borrowed, so neither copied nor moved.

As per the lifetime elision rules fn visuals(&self) -> &[Visualtype] is equivalent to fn visuals<'a>(&'a self) -> &'a [Visualtype].

2 Likes

If the unsafe block is sound, then safe Rust can't cause undefined behaviour, that's what is meant by soundness. The code is essentially performing a complicated pointer cast, and the function signatures ensure the correct lifetimes are picked up, so the borrow checker should prevent undefined behaviour outside the unsafe block.

1 Like