< 返回我的博客

cham-pin 发表于 2024-09-18 10:42

#[derive(Clone, Debug)]
pub struct Elem {
    inner: u8,
}

#[derive(Clone)]
#[repr(transparent)]
pub struct Dict{
    list : Vec<Elem>,
}

impl Dict {
    pub fn new() -> Self {
        Self {
            list: Vec::new()
        }
    }

    pub fn set(&mut self, elem: Elem) {
        self.list.push(elem)
    }

    pub fn len(&self) -> usize {
        self.list.len()
    }

    #[allow(invalid_reference_casting)]
    pub fn get_mut_unchecked(&self) -> &mut Self {
        unsafe {
            let ptr1 = self as *const Self;
            let ptr2 = ptr1 as *mut Self;
            &mut *ptr2
        }
    }
}


fn func(dict: &Dict) {
    let this = dict.get_mut_unchecked();
    let elem = Elem{inner:42};
    this.set(elem);
}


fn main() {
    let dict = Dict::new();
    func(&dict);
    println!("Hello, world! => len:{}", dict.len());

}

// --------------------- 我希望能通过回调获取数据,也就是dict.len()!=0; 但是实际上在release模式下传入dict的数据被优化掉了


rust版本:

rustc 1.80.0-nightly (867900499 2024-05-23)                                                                                                  
binary: rustc                                                                                                                                
commit-hash: 8679004993f08807289911d9f400f4ac4391d2bc                                                                                        
commit-date: 2024-05-23                                                                                                                      
host: x86_64-unknown-linux-gnu                                                                                                               
release: 1.80.0-nightly                                                                                                                      
LLVM version: 18.1.6   

评论区

写评论
amazinqc 2024-10-15 17:47

非常好bug

实际上需要使用UnsafeCell:

use std::cell:UnsafeCell;
struct Dict {
    list: UnsafeCell<Vec<u8>>
}

get_mut_unchecked本质是就是实现“内部可变性”的,但是这个本身是违反rust编译器的引用规则的,会被视为未定义行为,如果编译器判断某些代码对程序最终状态不产生影响,就会被优化掉。 UnsafeCell就是rust原语,专门用来实现内部可变性的,使用了UnsafeCell的结构也将获得对应的内部可变(&T -> &mut T),并且保证编译器不会错误优化。

use std::cell:UnsafeCell;
struct Dict {
    list: UnsafeCell<Vec<u8>>
}
impl Dict {
    pub fn list(&self) -> &mut Vec<u8> {
        unsafe { &mut *self.list.get() }
    }
    pub fn set(&self, elem: Elem) {
        self.list().push(elem)
    }
    pub fn len(&self) {
        self.list().len()
    }
    //...
}
作者 cham-pin 2024-09-18 11:14

如果func(dict: &Dict) 改成 func(dict: &mut Dict) 则上述问题就没有了

1 共 2 条评论, 1 页