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

时间:2018-11-12 14:06:30

标签: rust ffi unsafe

让我们考虑一下围绕C库的Rust包装器库。这个C库定义了一个结构,并将其用作整个API的可变指针。

Rust包装器定义了以下结构,其中ptr指向data

struct Wrapper {
    data: struct_from_c_t,
    ptr: *mut struct_from_c_t,
}

如果此指针的所有使用都在Wrapper结构的生存期内进行,那么在不安全的代码中使用此指针时,还会遇到其他潜在问题吗?

在此构造中取消引用和使用此指针是否总是安全的?

详细情况下,目标是能够使用此指针从不可更改地借用Wrapper的函数中调用此FFI函数。

1 个答案:

答案 0 :(得分:3)

这通常是一个坏主意,并且可能非常容易出错。

首先,请阅读Why can't I store a value and a reference to that value in the same struct?,深入了解为何安全Rust会在编译时阻止此构造。

TL; DR,如果您曾经移动func didSelect(_ segmentIndex: Int) { showHome.isHidden = segmentIndex != 0 showProfile.isHidden = segmentIndex != 1 showSettings.isHidden = segmentIndex != 2 // if you need to run other code based on the selected segment switch segmentIndex { case 0: // SHOWING THE HOME VIEW // do other stuff here... case 1: // SHOWING THE PROFILE VIEW // do other stuff here... case 2: // SHOWING THE SETTINGS VIEW // do other stuff here... default: break; } } 结构,则指针将无效。取消引用它会导致未定义的行为(一件坏事)。

如果您可以确保以下任何一项:

  1. Wrapper永远不会移动。
  2. 每次移动结构时,Wrapper都会更新。

然后,该指针将是有效且可以安全地取消引用(假定所有其他有关不安全代码的警告均得到保留)。


更糟糕的是,没有 reason 将指针放在首位;您可以在需要时引用一个值并将其转换为指针:

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) } } }

在没有上下文的情况下,这似乎是一个可疑的决定,但是Rust具有用于内部可变性的工具:

Wrapper