NLinker icon

UB with incorrect unsafe usage

NLinker | PRO | 05/16/19 05:43:55 AM UTC | 0 ⭐ | 982 👁️ | Never ⏰ | []
Rust |

1.25 KB

|

None

|

0 👍

/

0 👎

use std::cell::UnsafeCell;
 
pub struct OnceCell<T> {
    inner: UnsafeCell<Option<T>>,
}
 
impl<T> OnceCell<T> {
    pub fn new() -> OnceCell<T> { OnceCell { inner: UnsafeCell::new(None) } }
    pub fn get(&self) -> Option<&T> {
        unsafe { &*self.inner.get() }.as_ref()
    }
    pub fn set(&self, value: T) -> Result<(), T> {
        let slot = unsafe { &mut *self.inner.get() };
        if slot.is_some() {
            return Err(value);
        }
        *slot = Some(value);
        Ok(())
    }
 
    // UB!!!
    pub fn get_or_init(&self, f: impl FnOnce() -> T) -> &T {
        let slot = unsafe { &mut *self.inner.get() };
        match slot {
            None => {
                *slot = Some(f());
                slot.as_ref().unwrap()
            }
            Some(val) => val,
        }
    }
}
 
pub fn main() {
    let cell: OnceCell<Box<i32>> = OnceCell::new();
    let mut r1: Option<&i32> = None;
    let r2: &i32 = cell.get_or_init(|| {
        r1 = Some(cell.get_or_init(|| Box::new(1)));
//        r1 = Some(&*cell.get_or_init(|| Box::new(1)));
        Box::new(2)
    });
    let r1: &i32 = r1.unwrap();
    println!("{} {}", r1, r2);
}
/*
  result is like
~/rust ❯❯❯ ./once_cell
-1317687192 2
*/

Comments