如何泄露并释放Pin<Box>类型分配的堆指针?
处理Pin<Box>的指针泄露与清理
对于Pin<Box<T>>,我们可以通过以下方式安全地获取原始指针并在后续清理,核心是利用Rust的unsafe操作保证Pin的不变性(堆上对象不被移动):
步骤1:获取泄露的原始指针
有两种常见实现方式:
方式一:解开Pin取出Box后获取指针
通过Pin::into_inner_unchecked(unsafe)取出内部的Box<T>,再调用Box::into_raw获取指针。因为堆上的对象已被Pin固定,只要后续不移动该对象,此unsafe操作是安全的:
struct Pack { num: i32, _pin: PhantomPinned, } use std::marker::PhantomPinned; use std::pin::Pin; let pack = Box::pin(Pack { num: 100, _pin: PhantomPinned, }); // 获取泄露的指针 let leaked = unsafe { // 解开Pin取出Box:堆上对象不会被移动,操作安全 let boxed_pack = Pin::into_inner_unchecked(pack); Box::into_raw(boxed_pack) };
方式二:直接从Pin获取指针
利用Pin::as_ptr获取指向T的指针,转换为可变指针后使用。此方式无需解开Pin,只需确保指针来源合法:
// 基于上述已创建的pack let leaked = pack.as_ptr() as *mut Pack;
步骤2:后续清理释放指针
通过Box::from_raw(unsafe)将指针重新包装为Box<T>,之后可以选择重新Pin它(若需保持固定状态),或直接让Box被drop以释放内存:
清理并重新Pin
// 清理指针,重新包装为Pin<Box<Pack>> let _cleanup = unsafe { let boxed_pack = Box::from_raw(leaked); // 重新Pin:原对象始终在堆上未移动,操作安全 Pin::new_unchecked(boxed_pack) }; // _cleanup被drop时自动释放堆内存
直接清理(无需保留Pin状态)
如果不需要继续保持Pin状态,直接重建Box即可:
let _cleanup = unsafe { Box::from_raw(leaked) }; // Box被drop时自动释放内存
关键安全说明
所有unsafe操作的安全性基于以下前提:
- 原始指针必须来自合法的
Box分配(即Box::new或Box::pin创建的对象)。 - 指针指向的对象在泄露期间未被移动、释放或修改为无效状态。
- 清理时确保指针仅被使用一次(避免重复释放)。
内容的提问来源于stack exchange,提问作者rodrigocfd
相关产品推荐
相关产品推荐

