将数据和指向该数据的可变指针存储在结构中是否安全?
Is storing data and a mutable pointer to that data in a struct safe?
让我们考虑一个围绕 C 库的 Rust 包装器库。此 C 库定义了一个结构并将其用作整个 API.
的可变指针
Rust 包装器定义了以下结构 ptr
指向 data
。
struct Wrapper {
data: struct_from_c_t,
ptr: *mut struct_from_c_t,
}
如果此指针的所有使用都在 Wrapper
结构的生命周期内进行,那么在不安全代码中使用此指针时,我 运行 还会遇到哪些其他潜在问题?
在此构造中取消引用和使用此指针是否始终安全?
对于详细上下文,目标是能够使用此指针从函数借用 Wrapper
非可变地调用 FFI 函数。
这通常是一个 糟糕的主意,它很容易出错 。
首先,阅读 以深入了解为什么安全 Rust 在编译时阻止此构造。
TL;DR,如果您 曾经 移动 Wrapper
结构,指针将无效。取消引用它会导致未定义的行为(一件坏事)。
如果您可以确保:
Wrapper
从未动过。
- 每次移动结构时
ptr
都会更新。
那么指针将是有效的并且可以安全地取消引用(假设关于不安全代码的所有其他警告都得到遵守)。
更糟糕的是,没有理由将指针放在第一位;您可以在需要时获取对值的引用并将其转换为指针:
extern "C" {
fn ffi_fn(data: *mut struct_from_c_t);
}
struct Wrapper {
data: struct_from_c_t,
}
impl Wrapper {
fn do_thing(&mut self) {
unsafe { ffi_fn(&mut self.data) }
}
}
from functions borrowing Wrapper
non-mutably
没有上下文,这似乎是一个可疑的决定,但 Rust 有内部可变性的工具:
use std::cell::RefCell;
struct Wrapper {
data: RefCell<struct_from_c_t>,
}
impl Wrapper {
fn do_thing(&self) {
unsafe { ffi_fn(&mut *self.data.borrow_mut()) }
}
}
让我们考虑一个围绕 C 库的 Rust 包装器库。此 C 库定义了一个结构并将其用作整个 API.
的可变指针Rust 包装器定义了以下结构 ptr
指向 data
。
struct Wrapper {
data: struct_from_c_t,
ptr: *mut struct_from_c_t,
}
如果此指针的所有使用都在 Wrapper
结构的生命周期内进行,那么在不安全代码中使用此指针时,我 运行 还会遇到哪些其他潜在问题?
在此构造中取消引用和使用此指针是否始终安全?
对于详细上下文,目标是能够使用此指针从函数借用 Wrapper
非可变地调用 FFI 函数。
这通常是一个 糟糕的主意,它很容易出错 。
首先,阅读
TL;DR,如果您 曾经 移动 Wrapper
结构,指针将无效。取消引用它会导致未定义的行为(一件坏事)。
如果您可以确保:
Wrapper
从未动过。- 每次移动结构时
ptr
都会更新。
那么指针将是有效的并且可以安全地取消引用(假设关于不安全代码的所有其他警告都得到遵守)。
更糟糕的是,没有理由将指针放在第一位;您可以在需要时获取对值的引用并将其转换为指针:
extern "C" {
fn ffi_fn(data: *mut struct_from_c_t);
}
struct Wrapper {
data: struct_from_c_t,
}
impl Wrapper {
fn do_thing(&mut self) {
unsafe { ffi_fn(&mut self.data) }
}
}
from functions borrowing
Wrapper
non-mutably
没有上下文,这似乎是一个可疑的决定,但 Rust 有内部可变性的工具:
use std::cell::RefCell;
struct Wrapper {
data: RefCell<struct_from_c_t>,
}
impl Wrapper {
fn do_thing(&self) {
unsafe { ffi_fn(&mut *self.data.borrow_mut()) }
}
}