Rust中指针未释放却值突变,此现象是否为Bug?
Rust悬空指针与未定义行为问题解析
问题代码
fn test() -> *const Vec<u8> { let b = vec![9_u8]; let ret: *const Vec<u8> = &b; println!("ret ptr={:#p} inside {:#p}", ret, b.as_ptr()); std::mem::forget(b); ret } fn main() { let a = test(); let v = unsafe { &*a }; println!("ret ptr={:#p} inside {:#p} value={}", v, v.as_ptr(), v[0]); println!("ret ptr={:#p} inside {:#p} value={}", v, v.as_ptr(), v[0]); }
运行输出
ret ptr=0x00007fffc5d85690 inside 0x00005650a61cfaa0 ret ptr=0x00007fffc5d85690 inside 0x00005650a61cfaa0 value=9 ret ptr=0x00007fffc5d85690 inside 0x00005650a572a348 value=76
疑问解答
疑问1:为何该指针在Rust中未被释放就被垃圾回收?
首先纠正一个误解:Rust没有垃圾回收机制。问题核心在于内存区域的属性:
Vec<u8>变量b是分配在栈上的,当test函数执行完毕后,函数的栈帧会被销毁,栈上b占用的内存会被标记为可复用。std::mem::forget(b)只是阻止了Vec的析构函数运行,也就是不会释放Vec指向的堆内存,但完全不影响栈上b自身的内存回收。- 你返回的指针
ret指向的是栈上的b,所以函数返回后这个指针就成了悬空指针,指向的内存已经不属于当前有效的程序上下文了。
疑问2:最后一行输出中值突然发生变化,这是否属于Bug?
这不是Rust的Bug,而是**未定义行为(UB)**导致的不可预测结果:
- 在
main中通过unsafe { &*a }将悬空指针转为引用时,已经违反了Rust的安全规则——引用必须始终指向有效的、初始化的内存。 - 第一次打印时,栈上原
b的内存还没被其他操作覆盖,所以Vec的内部指针和数据值看起来正常;但第二次打印前,println!自身的调用会占用栈空间,覆盖了原栈上b的内容,导致Vec内部的指针被修改为随机地址,读取到的v[0]自然是随机值。 - 未定义行为的结果没有任何保证,不同编译环境、优化级别下可能出现崩溃、数据错乱或其他诡异表现,这完全是代码违反内存安全规则导致的。
内容的提问来源于stack exchange,提问作者Nour-eddine Taleb
相关产品推荐
相关产品推荐

