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

使用Rust的read_volatile和write_volatile时触发未定义行为错误

Rust中使用read_volatile/write_volatile计数的问题与解决方法

问题描述

尝试用Rust的read_volatile和write_volatile函数实现从0计数到10亿,编写的代码如下:

fn main() {
    let x = 0u32;
    let t = (&x as *const u32) as *mut u32;
    for _ in 0..1000000000 {
        unsafe {
            core::ptr::write_volatile(t, core::ptr::read_volatile(t) + 1);
        }
    }
    println!("{:?}", x)
}

运行后触发编译错误:

error: assigning to &T is undefined behavior, consider using an UnsafeCell
--> src/main.rs:30:13
|
27 | let t = (&x as *const u32) as *mut u32;
| ------------------------------ casting happened here
...

core::ptr::write_volatile(t, core::ptr::read_volatile(t) + 1);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

= note: for more information, visit https://doc.rust-lang.org/book/ch15-05-interior-mutability.html
= note: #[deny(invalid_reference_casting)] on by default

问题根源

Rust的内存安全规则明确:&T类型的不可变引用保证指向的值不会被修改。将不可变引用强制转换为可变指针并执行写入操作,属于未定义行为,编译器通过默认启用的invalid_reference_casting规则阻止这种违反安全模型的操作。

修复方案

要在持有不可变访问权限时修改内部值,必须使用UnsafeCell——这是Rust中唯一合法支持内部可变性的底层类型。修改后的代码如下:

use std::cell::UnsafeCell;

fn main() {
    let x = UnsafeCell::new(0u32);
    let t = x.get(); // 直接获取合法的*mut u32指针,无需强制转换
    for _ in 0..1000000000 {
        unsafe {
            let current = core::ptr::read_volatile(t);
            core::ptr::write_volatile(t, current + 1);
        }
    }
    // 读取最终值时必须用read_volatile,确保编译器不优化读取操作
    let result = unsafe { core::ptr::read_volatile(t) };
    println!("{:?}", result);
}

核心要点说明

  • UnsafeCell::get()方法返回的*mut T指针符合Rust的安全约定,不会触发编译错误。
  • 读取最终值时必须使用read_volatile,因为之前的写入是volatile操作,需要确保读取到最新的内存值,避免编译器因优化省略读取步骤。
  • 代码中的unsafe块是必要的,因为volatile内存操作和直接指针访问属于不安全操作,需要开发者自行保证内存安全(比如避免多线程竞争,若需要多线程场景还需配合原子类型)。

内容的提问来源于stack exchange,提问作者Lokesh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 18:03:34