gpt4 book ai didi

rust - 当切片不为空时,为什么 Box::from_raw 使用指向切片数据的指针?

转载 作者:行者123 更新时间:2023-12-03 11:37:10 25 4
gpt4 key购买 nike

我写了一些 Rust 代码,为一些 C 代码提供了 FFI,我最近发现了一个错误。结果不安全很困难而且容易出错——谁知道呢!我想我已经修复了这个错误,但我很想更多地了解这个问题。
一个函数花了 Vec , 称为 into_boxed_slice在它上面并将指针(通过 as_mut_ptr )和长度返回给调用者。它叫 mem:forgetBox在回来之前。
对应的“free”函数只接受指针并调用Box::from_raw用它。现在这是错误的,但是未定义行为的惊人之处在于它可以在大多数时间工作。而这做到了。除非来源Vec段错误时为空。另外值得注意的是,MIRI 正确识别了问题:“未定义行为:入站测试失败:0x4 不是有效指针”。
无论如何,修复方法也是采用自由函数中的长度,重建切片,然后 Box::from_raw那。例如。 Box::from_raw(slice::from_raw_parts_mut(p, len))我试图在这个操场上捕捉所有这些:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7fe80cb9f0c5c1eee4ac821e58787f17
这是供引用的游乐场代码:

use std::slice;

fn main() {
// This one does not crash
demo(vec![1]);

// These do not crash
hopefully_correct(vec![2]);
hopefully_correct(vec![]);

// This one seg faults
demo(vec![]);
}

// MIRI complains about UB in this one (in Box::from_raw)
fn demo(v: Vec<i32>) {
let mut s: Box<[i32]> = dbg!(v.into_boxed_slice());
let p: *mut i32 = dbg!(s.as_mut_ptr());
assert!(!p.is_null());
std::mem::forget(s);
// Pretend the pointer is returned to an FFI interface here

// Imagine this is the free function counterpart to the imaginary FFI.
unsafe { Box::from_raw(p) };
}

// MIRI does not complain about this one
fn hopefully_correct(v: Vec<i32>) {
let mut s: Box<[i32]> = dbg!(v.into_boxed_slice());
let p: *mut i32 = dbg!(s.as_mut_ptr());
let len = s.len();
assert!(!p.is_null());
std::mem::forget(s);
// Pretend the pointer is returned to an FFI interface here

// Imagine this is the free function counterpart to the imaginary FFI.
unsafe { Box::from_raw(slice::from_raw_parts_mut(p, len)) };
}
我已经浏览了 Box source 并进行了大量搜索,但我不清楚重建切片有何帮助。似乎指针是相同的,但在固定示例中的某处正确处理了一些空优化,可能作为 Unique 的一部分?
谁能解释一下这里发生了什么?
我发现这三个链接很有用,但不足以回答我的问题:
  • How to expose a Rust Vec<T> to FFI?
  • How to pass a boxed slice ( Box<[T]> ) to a C function?
  • Box<[T]>::into_raw is useless
  • 最佳答案

    那是因为当您解构空向量时,您会得到一个空指针和零长度。
    当您调用 Box::from_raw (null) ,你打破了一个盒子不变量:" Box<T> values will always be fully aligned, non-null pointers" .然后当 Rust 放下盒子时,它会尝试释放空指针。
    OTOH 打电话时slice::from_raw_parts , Rust 分配一个包含空指针和零长度的新胖指针,然后 Box::from_rawBox 中存储对此胖指针的引用.当丢弃盒子时,Rust 首先丢弃切片(它知道长度为零意味着不需要释放的空数据),然后为胖指针释放内存。
    另请注意,在非工作情况下,您将重建 Box<i32> ,而在工作案例中,您重建一个 Box<[i32]> , 如您尝试编译以下代码所示:

    use std::slice;

    fn demo(v: Vec<i32>) {
    let mut s: Box<[i32]> = dbg!(v.into_boxed_slice());
    let p: *mut i32 = dbg!(s.as_mut_ptr());
    assert!(!p.is_null());
    std::mem::forget(s);
    // Pretend the pointer is returned to an FFI interface here

    // Imagine this is the free function counterpart to the imaginary FFI.
    let _b: () = unsafe { Box::from_raw(p) };
    }

    // MIRI does not complain about this one
    fn hopefully_correct(v: Vec<i32>) {
    let mut s: Box<[i32]> = dbg!(v.into_boxed_slice());
    let p: *mut i32 = dbg!(s.as_mut_ptr());
    let len = s.len();
    assert!(!p.is_null());
    std::mem::forget(s);
    // Pretend the pointer is returned to an FFI interface here

    // Imagine this is the free function counterpart to the imaginary FFI.
    let _b: () = unsafe { Box::from_raw(slice::from_raw_parts_mut(p, len)) };
    }
    Playground

    关于rust - 当切片不为空时,为什么 Box::from_raw 使用指向切片数据的指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62708492/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com