将数据和指向该数据的可变指针存储在结构中是否安全?

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 结构,指针将无效。取消引用它会导致未定义的行为(一件坏事)。

如果您可以确保:

  1. Wrapper 从未动过。
  2. 每次移动结构时 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()) }
    }
}