使用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
&Tis undefined behavior, consider using anUnsafeCell
--> 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
相关产品推荐
相关产品推荐

