You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Rust中,对来源(provenance)与可变引用重叠的裸指针执行位置投影(place projection)是否安全?

在Rust中,对来源(provenance)与可变引用重叠的裸指针执行位置投影(place projection)是否安全?

首先给你一颗定心丸:你写的这段代码(包括标记(*)的那行)在当前Rust实现中是安全的,而且根据Rust内存模型的设计方向,未来也会被认定为合法操作。我们一步步拆解背后的逻辑:

核心:投影操作到底在做什么?

你担心的(*c.get()).1看起来像是解引用了UnsafeCell内部的整个元组,但实际上Rust的编译器和内存模型(比如Stacked Borrows或Tree Borrows)会把这个操作拆解成纯粹的地址计算步骤:

  1. 通过c.get()拿到指向元组的裸指针(其provenance覆盖整个元组的内存)
  2. 利用元组的内存布局计算第二个u64元素的偏移量,最终得到指向该元素的裸指针并转换为可变引用d

关键在于:这里的*c.get()并没有实际访问整个元组的内存——它只是一个语法上的"占位符",用来告诉编译器如何推导子元素的地址。你既没有读取整个元组的值、也没有写入它,更没有为整个元组创建任何引用,所以完全不会触发和b的别名冲突。

内存模型的核心原则:独占性针对内存区域,而非整个provenance

Rust可变引用的独占性规则本质是:同一时间,同一个内存区域不能有两个活跃的可变引用,也不能存在可变引用与共享引用/裸指针的访问冲突。

在你的代码里:

  • b指向元组的第一个u64(独立内存区域A)
  • d指向元组的第二个u64(独立内存区域B)

两个区域完全不重叠,它们的存在和访问不会互相干扰。哪怕你是通过整个元组的provenance计算B的地址,只要没有实际访问A和B的重叠区域(这里根本不存在重叠),就不会违反独占性规则。Miri两种内存模型都通过检查,正是因为它识别到了这一点:你只是在做地址计算,没有对整个元组的内存进行任何触发冲突的操作。

关于文档表述的补充

你提到的Rust文档可能表述不够精确,但实际内存模型的逻辑比字面意思更细致。文档中"创建可变引用时,该引用存在期间,其指向的内存不能通过其他非派生的指针/引用访问"的规则,这里的"其指向的内存"指的是该引用实际覆盖的具体内存区域,而非整个provenance对应的更大内存块。你的d指向的区域和b完全无关,所以这条规则并不适用。

而你提到的"创建同一区域的共享引用不使用再写"的UB场景,本质是共享引用的创建已经标记该内存区域为共享访问,和可变引用的独占性冲突;但你的代码里并没有为整个元组创建任何引用,只是做了地址计算,完全是两回事。

安全操作的边界

只要满足以下两个条件,这种投影操作就是安全的:

  • 最终得到的可变引用指向的内存区域,和已有的可变引用指向的区域完全不重叠
  • 投影的中间步骤(比如*c.get())没有实际访问整个更大的内存块(即没有读、写、创建该块的引用)

你的代码完全符合这两个条件,所以不仅现在能正常工作,未来也会被Rust的内存模型所允许。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 10:38:01