【问题标题】:References in rust self referential structsRust 自引用结构中的引用
【发布时间】:2023-02-05 07:11:15
【问题描述】:

给出下面的代码 sn-p:

use std::{io::BufWriter, pin::Pin};

pub struct SelfReferential {
    pub writer: BufWriter<&'static mut [u8]>, // borrowed from buffer
    pub buffer: Pin<Box<[u8]>>, 
}

#[cfg(test)]
mod tests {
    use std::io::Write;

    use super::*;
    fn init() -> SelfReferential {
        let mut buffer = Pin::new(vec![0; 12].into_boxed_slice());
        let writer = unsafe { buffer.as_mut().get_unchecked_mut() };
        let writer = unsafe { (writer as *mut [u8]).as_mut().unwrap() };
        let writer = BufWriter::new(writer);
        SelfReferential { writer, buffer }
    }

    #[test]
    fn move_works() {
        let mut sr = init();
        sr.writer.write(b"hello ").unwrap();
        sr.writer.flush().unwrap();
        let mut slice = &mut sr.buffer[6..];
        slice.write(b"world!").unwrap();
        assert_eq!(&sr.buffer[..], b"hello world!".as_ref());

        let mut sr_moved = sr;
        sr_moved.writer.write(b"W").unwrap();
        sr_moved.writer.flush().unwrap();
        assert_eq!(&sr_moved.buffer[..], b"hello World!".as_ref());
    }
}

第一个问题:将'static生命周期分配给BufWriter中的可变切片引用是否可以?从技术上讲,它绑定到结构实例本身的生命周期,据我所知,没有安全的方法可以使它无效。

第二个问题:除了这种类型的不安全实例化这一事实,在测试示例中,在底层缓冲区中创建了两个可变引用,是否还有与这种“单一”(由于缺乏更好的词)类型相关的任何其他潜在危险?

【问题讨论】:

    标签: rust undefined-behavior unsafe


    【解决方案1】:

    可以将'static 生命周期分配给BufWriter 中的可变切片引用吗?

    有点,但还有一个更大的问题。生命本身并不比任何其他选择差,因为有您可以在此处使用的生命周期非常准确。但这样做并不安全暴露该参考,因为那时可以采用:

    let w = BufWriter<&'static mut [u8]> = {
        let sr = init();
        sr.writer
    };
    // `sr.buffer` has now been dropped, so `w` has a dangling reference
    

    这种“单一”(因为缺少更好的词)类型是否还有其他潜在危险?

    是的,这是未定义的行为。 Box 不是只是管理分配;它还(目前)表示对内容的唯一、无混叠访问的声明。您通过创建 writer 然后移动 buffer 违反了非别名 - 即使堆内存实际上并没有被触及,buffer 的移动被认为是使所有对它的引用无效。

    这是 Rust 语义的一个领域,尚未完全确定,但就当前编译器而言,这是 UB。如果您在 Miri 解释器下运行您的测试代码,您可以看到这一点。


    好消息是,你正在尝试做的是一个非常普遍的愿望,人们已经在解决这个问题。我个人推荐使用ouroboros——在宏的帮助下,它允许你创建你想要的结构无需编写任何新的不安全代码。writer 的使用方式会有一些限制,但没有什么是你不能通过写 impl io::Write for SelfReferential 来解决的。这个空间中另一个较新的库是yoke;我没试过。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-14
      • 1970-01-01
      • 2016-12-23
      • 2017-01-19
      相关资源
      最近更新 更多