Why doesn't the code panic in unsafe code with `cannot return value referencing local variable shard`?

pub struct Ref<'a, K, V, S = RandomState> {
    _guard: RwLockReadGuard<'a, HashMap<K, V, S>>,
    k: &'a K,
    v: &'a V,
}

pub struct SharedValue<T> {
    value: UnsafeCell<T>,
}

unsafe fn _yield_read_shard(&'a self, i: usize) -> RwLockReadGuard<'a, HashMap<K, V, S>> {
     debug_assert!(i < self.shards.len());

     self.shards.get_unchecked(i).read()
}

fn _get<Q>(&'a self, key: &Q) -> Option<Ref<'a, K, V, S>>
    where
        K: Borrow<Q>,
        Q: Hash + Eq + ?Sized,
{
    let hash = self.hash_usize(&key);

    let idx = self.determine_shard(hash);

    let shard = unsafe { self._yield_read_shard(idx) };

    if let Some((kptr, vptr)) = shard.get_key_value(key) {
        unsafe {
            let kptr = &*(kptr as *const K);

            let vptr = &*(vptr as *const SharedValue<V>);

            Some(Ref::new(shard, kptr, vptr.get()))
        }
    } 
    else {
        None
    }
}

The ownership of variable shard belongs to the _get function, but in the end the function returns a Ref that causes shard to move, besides the code doesn't panic with any error(e.g. cannot return value referencing local variable shard), why is that?(above code is from dashmap)

It seems like shard is a kind of reference to something else. Returning a reference isn't necessarily a problem as long as what it points to remains alive.

1 Like

Sorry, I am not clear, is the value returned by _yield_read_shard reference type? isn't value returned a RwLockReadGuard struct?:rofl:

That's a reference and a pointer.

pub struct RwLockReadGuard<'a, T: 'a + ?Sized> {
    lock: &'a AtomicUsize,
    data: NonNull<T>,
}

You can return local variables that contain references to non-locals. Note how in _get the lifetime is threaded from &'a self to Ref<'a, ...>.

2 Likes

Got it!
:+1: :+1: :+1:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.