使用闭包从Option中获取原始指针是否安全?

问题描述 投票:1回答:1

我有一个Option<&T>,我想有一个原始的*const T,如果选项是None,则为null。我想包装一个FFI调用,该调用带有一个指向Rust分配对象的指针。

另外,我使用的FFI接口具有借用语义(我分配一些内容并传入指向它的指针),而不是所有权语义

extern "C" {
    // Parameter may be null
    fn ffi_call(*const T);
}

fn safe_wrapper(opt: Option<&T>) {
    let ptr: *const T = ???;
    unsafe { ffi_call(ptr) }
}

我可以使用match语句来执行此操作,但该方法感觉非常冗长。

let ptr = match opt {
    Some(inner) => inner as *const T,
    None => null(),
};

我也可以将引用映射到指针,然后使用unwrap_or

let ptr = opt.map(|inner| inner as *const T).unwrap_or(null());

但是,我担心指针在通过闭包时可能会失效。 Rust是否保证最终指针指向与原始引用相同的东西?如果TCopy,这是否会以有意义的方式改变语义?有没有更好的方式让我俯瞰?

rust
1个回答
2
投票

是的,这是安全的。我把它写成:

use std::ptr;

fn safe_wrapper(opt: Option<&u8>) {
    let p = opt.map_or_else(ptr::null, |x| x);
    unsafe { ffi_call(p) }
}

如果你发现自己写了很多东西,你可以把它变成一个特征并将其减少到单个方法调用。

指针在通过闭包时可能会失效

可能是,如果你以某种方式自己使它无效。因为函数需要引用,所以你肯定知道引用的值在函数调用的持续时间内是有效的 - 这就是Rust的借用检查器的目的。

指针变为无效的唯一方法是更改​​指针的值(例如,向其添加偏移量)。既然你不这样做,那很好。

Rust是否保证最终指针指向与原始引用相同的东西?

这取决于你对“最终”的意思。将引用转换为指针将始终导致两个值在内存中包含相同的位置。其他任何东西都是故意恶意的,没有人会用Rust开始。

如果TCopy,这是否会以有意义的方式改变语义?

不。此外,我们正在讨论&T,它始终是Copy

也可以看看:


我正在使用的FFI接口具有借用语义(我分配一些东西并传入指向它的指针),而不是所有权语义

需要明确的是,您无法仅根据函数类型来确定所有权。

此C函数取得所有权:

void string_free(char *)

这个C函数借用:

size_t string_len(char *)

两者都拿一个指针。 Rust通过明确界定什么是借款以及什么是所有权转让来改善这种情况。

extern "C" {
    // Parameter may be null
    fn ffi_call(*const T);
}

这段代码是荒谬的;它没有定义泛型类型T,FFI函数无论如何都不能有泛型类型。

© www.soinside.com 2019 - 2024. All rights reserved.