Rust 为什么slice::from_raw_零件的寿命很重要?

Rust 为什么slice::from_raw_零件的寿命很重要?,rust,ffi,lifetime,Rust,Ffi,Lifetime,slice::from_raw_parts的文档警告程序员用正确的生命周期注释切片。我假设,给定一些生命周期'a,我可以使用 let myslice: &'a mut [i32] = std::slice::from_raw_parts_mut(ptr, sz) 我还假设 由于myslice是一个引用,它与ptr所指向的底层数据的分配/解除分配无关。生存期注释不会影响数据的内存管理 对于myslice本身(即,包含指针和大小的结构),内存管理没有什么困难。它与任何其他结构或i32一样

slice::from_raw_parts
的文档警告程序员用正确的生命周期注释切片。我假设,给定一些生命周期
'a
,我可以使用

let myslice: &'a mut [i32] = std::slice::from_raw_parts_mut(ptr, sz)
我还假设

  • 由于
    myslice
    是一个引用,它与ptr所指向的底层数据的分配/解除分配无关。生存期注释不会影响数据的内存管理
  • 对于
    myslice
    本身(即,包含指针和大小的结构),内存管理没有什么困难。它与任何其他结构或
    i32
    一样。如果我把它放在
    框中
    ,那么
    std::raw::slice
    结构将在
    死亡时解除分配。当然,切片引用的数据不会被释放。生存期不会影响片的内存管理

为什么正确的人生观很重要?在设置切片生存期时,释放后使用是唯一需要担心的危险吗?

更新:正如delnan所说,可变别名是一个真正的问题,可能是由于设置了不正确的生存期而引起的。有关更多详细信息,请参见他/她的答案

旧答案 在设置切片寿命时,免费使用确实是唯一需要担心的危险。编译器将信任您,并假定切片所指向的数据与您指定的生存期一样长。如果带注释的生存期比基础数据的实际生存期长,则可能会在释放bug后使用(当数据已被释放时,您将能够使用切片)


关于你的假设,它们是正确的。生存期注释对数据的内存管理没有任何影响。

空闲后使用是而不是唯一的危险。使用错误的生存期,可能会导致可变别名。让我们以这个(人为的)函数为例:

fn duplicate_mut_slice<'a, T>(xs: &mut [T]) -> &'a mut [T] {
    let ptr = xs.as_mut_ptr(); // btw, this part is safe!
    unsafe { std::slice::from_raw_parts_mut(ptr, xs.len()) }
}
fn重复的多个切片(&mut T T,&mut T T){
设a=重复的多个切片(xs);
设b=重复的多个切片(xs);
(&mut a[0],&mut b[0])
}

请注意,在第二个函数的签名中,生命周期是正确的,释放后使用不会(立即)造成危险。但可变别名非常隐蔽。基本上,一切都依赖于保证不存在可变别名,以防止出现诸如竞争条件、迭代器无效、逻辑错误等问题,并在释放后使用(由
T
管理的内容)。使用可变别名几乎可以引起任何可以想象的问题。

免费后使用是否还不够危险?很多安全漏洞都是因为这样的原因而发生的。(谢谢;我修正了打字错误)。这很危险:)。我只是担心还有一些我不得不担心的事情。值得注意的是,释放后使用基本上会导致任何其他内存安全问题,因为它会导致任意堆损坏(例如,UAF可能会更改表示某个数组长度的内存,然后对该数组的后续访问可能会超出范围)。(事实上,大多数内存安全问题都是如此:它们中的每一个都可能产生连锁反应,导致您可以想象的任何其他内存安全问题。)
fn alias_first_element<T>(xs: &mut [T]) -> (&mut T, &mut T) {
    let a = duplicate_mut_slice(xs);
    let b = duplicate_mut_slice(xs);
    (&mut a[0], &mut b[0])
}