Rust中从指针复制Box后如何避免二次释放问题?
Rust中重复Box导致的双释放问题及正确处理方式
问题重现
以下代码会触发双释放错误:
let a = Box::new(100); let b = unsafe { ptr::read(&a) };
程序退出时抛出错误:
sm2-be78471d87150ecc(39668,0x7000075d5000) malloc: *** error for object 0x6000025e0000: pointer being freed was not allocated
错误原因
ptr::read(&a)直接复制了Box实例的内部指针,导致a和b两个Box持有同一块堆内存地址。当两个Box各自离开作用域触发Drop时,会尝试两次释放同一块内存,触发内存安全错误。
可选方案分析与正确结论
方案一:使用ManuallyDrop包裹第二个Box
let a = Box::new(100); let b = ManuallyDrop::new(unsafe { ptr::read(&a) });
这个方案不会造成内存泄漏:a会在离开作用域时正常释放堆内存,而ManuallyDrop包裹的b不会自动执行Drop,因此不会触发双释放。但要注意,后续不能再访问b指向的内存,否则会访问已释放的悬空指针。
方案二:使用mem::forget跳过第二个Box的析构
let a = Box::new(100); let b = unsafe { ptr::read(&a) }; mem::forget(b);
这个方案是正确的。mem::forget(b)明确阻止b的析构函数执行,仅保留a作为内存的唯一所有者,在a离开作用域时正常释放堆内存,既避免了双释放,也不会造成内存泄漏。
总结
如果需要通过ptr::read复制Box指针,核心原则是确保只有一个Box实例执行析构函数。mem::forget是更直观的选择,它清晰表达了“不执行该值析构”的意图;ManuallyDrop也能实现相同效果,但需要注意避免后续的悬空指针访问。
内容的提问来源于stack exchange,提问作者Victor Ermolaev
相关产品推荐
相关产品推荐

