当前位置: 首页 > 知识库问答 >
问题:

如何安全地创建不安全的?

阙阳
2023-03-14

UnsafeCell文档中说

不完美

唯一的施工方法是:

pub const fn new(value: T) -> UnsafeCell<T>

但是,不可能创建c_void,我们只能创建*mut c_void*const c_void

是否可以创建UnsecCell

还是没有必要?即使我们知道某个外国金融机构的电话会改变它所指向的数据,并且我们有多个引用,我们是否可以始终使用*mut c_void

一个用例将是:

struct FFIStruct { v: UnsafeCell<c_void>, other_fields: ... }
impl FFIStruct {
    // We don't want to require &mut self, as we 
    // are sure private call_ffi() will always be called 
    // sequentially, and we don't want to stop
    // status() being callable during the call
    fn call_ffi(&self){ ffi_function(self.v.get()) }
    pub fn status(&self) -> FFIStatus { ... }
}

现在我们如何创建FFIStruct?或者只使用*mut c_void就可以了?

需要#![功能(as_cell)]

unsafe fn get_cell<'a>(p: *mut c_void) -> &'a Cell<c_void> {
    Cell::from_mut(&mut *p)
}

共有2个答案

商勇
2023-03-14

在Rust论坛的一些内部讨论和关于RFC 1861的讨论之后,我意识到c_void只是一个常见的解决方法,并且存在其他选项,例如结构不透明

所以我得出结论,我需要的是*const UnsafeCell

  • 这是一个原始指针,所以适合立即发送到FFI;
  • 原始指针假定const,意味着任何对*mut T的转换都会UB和程序员应该避免它。这可以保护它指向的内存在Rust中被修改(除非通过UnsecCell,原因);
  • 它包含UnsecCell,因此它意味着内部可变性。这证明FFI函数能够对其进行变异是合理的;
  • 无法创建c_void,因此对于UnsecCell

降级:

use std::cell::UnsafeCell;
use std::os::raw::c_void;

//Let's say all those functions are in an FFI module,
//with the exact same behaviour
fn ffi_create() -> *mut c_void {
    Box::into_raw(Box::new(0u8)) as *mut c_void
}
unsafe fn ffi_write_u8(p: *mut c_void, v:u8) {
    *(p as *mut u8) = v;
}
unsafe fn ffi_read_u8(p: *mut c_void) -> u8 {
    *(p as *mut u8)
}

fn main() {
    unsafe {
        //let's ignore ffi_destroy() for now
        let pointer = ffi_create() as *const UnsafeCell<c_void>;
        let ref_pointer = &pointer;        
        ffi_write_u8((&*pointer).get(), 7);
        let integer = ffi_read_u8((&**ref_pointer).get());
        assert_eq!(integer, 7);
    }
}

有趣的是,在*mut c_void*const UnsafeCell>之间转换是多么容易且符合人体工程学(但又富有表现力)

孔君浩
2023-03-14

TL;医生:只需使用*mut Foo。这里不需要任何类型的细胞。

免责声明:目前还没有正式的锈迹记忆模型。

无法创建此类型period,因为无法1创建c_void的实例。

问题是,你不需要创建这样的类型。别名不是空间的,而是时间的。你可以让多个*mut指向同一个地方,这并不重要,除非你尝试访问一个。这实质上是将其转换为一个引用,在该引用存在时,需要支持别名要求。

原始指针不属于Rust的安全内存模型。

-Rustonomicon酒店

与引用和智能指针不同,原始指针:

  • 允许通过将不可变和可变指针或多个可变指针同时指向同一位置来忽略借用规则
  • 不能保证指向有效内存
  • 允许为空
  • 不要实施任何自动清理

Rust编程语言

另见:

  • 为什么通过原始指针修改可变引用的值不会违反Rust的别名规则

1从技术上讲,您可以,但这只是因为实现和向后兼容性限制。

 类似资料:
  • 问题内容: 检查文件目录是否存在的最优雅方法是什么(如果不存在),使用Python创建目录?这是我尝试过的: 不知何故,我想念(感谢魔芋,布莱尔和道格拉斯)。这就是我现在所拥有的: 是否有“打开”标志,使它自动发生? 问题答案: 在Python≥3.5上,使用: 对于较旧的Python版本,我看到两个质量不错的答案,每个答案都有一个小缺陷,因此我将对此进行说明: 试试看,然后考虑创建。 如注释和其

  • 问题内容: 我正在创建要执行的JEXL脚本的沙箱,以使恶意用户无法访问我们为其提供访问权限的变量之外的数据,也无法在服务器上执行DOS攻击。我想为其他这样做的人提供文档,也让其他人对此方法有所投入。 以下是我知道需要解决的问题的列表: 仅允许使用白名单上的“ new”实例化类。 不允许访问任何类的getClass方法,因为这样便可以调用forName并且可以访问任何类。 限制对文件等资源的访问。

  • 输入安全 虽然ThinkPHP的底层安全防护比之前版本要强大不少,但永远不要相信用户提交的数据,建议务必遵守下面规则: 设置public目录为唯一对外访问目录,不要把资源文件放入应用目录; 开启表单令牌验证避免数据的重复提交,能起到CSRF防御作用; 使用框架提供的请求变量获取方法(Request类param方法及input助手函数)而不是原生系统变量获取用户输入数据; 对不同的应用需求设置def

  • 问题内容: 假设您有一个用于处理某种XML文件或配置文件的库。该库将整个文件读入内存,并提供用于编辑内容的方法。处理完内容后,可以调用将内容保存回文件。问题是如何以安全的方式执行此操作。 覆盖现有文件(开始写入原始文件)显然是不安全的。如果该方法在完成之前失败,则最终将写入一半的文件,并且您丢失了数据。 更好的选择是在某个位置写入 临时 文件,方法完成后, 将 临时文件 复制 到原始文件。 现在,

  • 虽然可以在Java 8中序列化lambda,但强烈建议不要这样做;甚至不鼓励序列化内部类。给出的原因是lambdas可能无法在另一个JRE上正确反序列化。然而,这是否意味着有一种方法可以安全地序列化lambda? 例如,假设我定义一个类如下: 如果像这样声明了类的实例,则不应序列化它: 但如果我创建一个这样的类实例,会怎么样: 现在序列化是安全的吗?我的直觉告诉我,是的,它应该是安全的,因为没有理

  • 问题内容: 我正在使用node.js的WSwebsocket库。目前,我正在运行ws服务器。现在,我想通过使用安全连接(即通过实施wss协议以及库支持TLS连接)来保护此连接。我进行了一些搜索,发现这很容易确保安全:wss和具有自签名证书的wss。 两者都不是很详细,第二个链接上的文章介绍了带有自签名证书的wss。我想知道的是,仅创建自签名证书并部署到我的生产环境是否就足够了?还是我需要像创建HT