Rust使用std::ptr::read时触发double-free错误如何解决
问题根因
触发double free的核心是对ptr::read的API契约和Rust所有权规则理解偏差,你写的mem::forget完全没有起到预期作用:
ptr::read的行为是按位拷贝指针指向位置的内存内容,生成一个新的所有权实例,这个操作不会转移原位置值的所有权,原位置的变量仍然会在作用域结束时正常析构。- 你调用
mem::forget(&value)是无效操作:mem::forget接收的是需要被跳过析构的值本身,你传入的是对局部变量value的引用,等于仅对一个无析构逻辑的引用类型执行了forget,完全不会影响value的析构流程。 - 你返回的
value是和原变量test共享同一块堆内存的String实例:这个返回值在println!执行完成后会被自动析构,第一次释放字符串的堆内存;后续不管是第二次调用函数再次拷贝出指向同一块已释放内存的String再析构,还是main函数结束时原test变量自动析构,都会重复释放同一块内存,直接触发double free错误。
修复方案
如果你的需求是根据引用拿到值的副本,完全不需要使用unsafe操作,直接用克隆语义即可:
fn get_value_from_ptr<T: Clone>(val: &T) -> T { val.clone() } fn main() { let test = String::from("hello!"); println!("{}", get_value_from_ptr(&test)); println!("{}", get_value_from_ptr(&test)); }
如果你确实需要使用ptr::read做底层操作,必须严格遵守API的安全契约:从一个位置read出值之后,必须保证原位置的内存不会被再次正常析构,否则必然会出现两个所有权实例指向同一块内存的问题,触发未定义行为。
以下是仅做演示的unsafe写法(实际业务中除非必要不要这么写):
use std::ptr; use std::mem; fn main() { let test = String::from("hello!"); println!("{}", get_value_from_ptr(&test)); // 禁止再次访问test,它的逻辑所有权已经被移走,再次访问属于未定义行为 mem::forget(test); // 跳过原变量的析构流程,避免重复释放 } fn get_value_from_ptr<T>(val: &T) -> T { unsafe { ptr::read(val) } }
注意:
ptr::read属于unsafe函数,调用时必须手动遵守上述安全契约,编译器不会帮你做任何所有权检查。
内容的提问来源于stack exchange,提问作者aiocat
相关产品推荐
相关产品推荐

