Rust中对Rc<RefCell<>>强制转换时指针地址偏移问题
Rc指针偏移问题解析
示例代码
use std::cell::RefCell; use std::rc::Rc; pub struct Foo<'a> { pub data: Rc<RefCell<&'a mut [u8]>>, } fn main() { let x: u64 = 0x300007f50; let x_addr: u64 = &x as *const u64 as u64; unsafe { #[allow(invalid_reference_casting)] let x = &mut *(x_addr as *mut Foo); println!("{:?}", x.data.as_ptr()); } }
程序输出
该程序的输出为:0x300007f68
原因分析
你遇到的问题本质是非法内存类型转换加上Rc<T>的内部结构导致的指针偏移,拆解如下:
非法的内存类型转换
你将存储u64值0x300007f50的内存地址,强制转换成*mut Foo指针,相当于把这段仅存一个u64值的内存,当作Foo结构体实例来解析。但这段内存的布局完全不符合Foo的结构要求,后续操作本质是在读取无意义的内存数据。Rc<T>的内部结构导致偏移Rc<T>是Rust的单线程引用计数智能指针,它的内部包含一个堆上控制块,结构大致为:
struct RcBox<T> { strong: std::cell::Cell<usize>, // 强引用计数 weak: std::cell::Cell<usize>, // 弱引用计数 value: T, // 实际存储的数据 }
Rc<T>实例本身只是一个指向该控制块的指针。当调用Rc::as_ptr()时,返回的是控制块中value字段的地址——也就是Rc指针地址加上控制块前两个字段的字节数(64位系统下每个计数占8字节,共16字节),再加上内存对齐填充(此处为额外8字节,总偏移24字节即0x18)。
在你的代码中,被当作Rc指针的是原u64值0x300007f50,所以as_ptr()返回的地址就是0x300007f50 + 0x18 = 0x300007f68,这就是你看到的偏移结果。
- 预期错误的根源
你误以为将u64值的地址转换成Foo指针后,x.data.as_ptr()会返回原u64的值,但实际上:
x.data是从非法内存中解析出的Rc实例,其内部指针是原u64的值0x300007f50as_ptr()返回的是该Rc指向的控制块中数据区域的地址,而非Rc指针本身或原u64的值
内容的提问来源于stack exchange,提问作者Suraj Choudhary
相关产品推荐
相关产品推荐

