Is there a resource leak problem when using pre-writing?
⚓ Rust 📅 2026-02-27 👤 surdeus 👁️ 3I've been practicing implementing a oneshot channel recently, and here's how the send method is implemented:
struct Inner<T> {
state: AtomicU32,
data: UnsafeCell<MaybeUninit<T>>,
}
impl<T> Inner<T> {
const unsafe fn write(&self, val: &T) {
unsafe {
let uninit = &mut *self.data.get();
std::ptr::copy_nonoverlapping(val, uninit.as_mut_ptr(), 1);
};
}
fn send(&self, val: T) -> Result<(), T> {
let mut status = Status::new(&self.state);
if status.is_closed() {
return Err(val);
}
// Pre-write. Since send is only called once, no additional checks are needed here
// SAFETY: Single write, and status(!ready) ensures the receiver won't access data, as ready is only set later
// Note: Before ready confirmation, there will be two copies of T data at the byte level in memory,
// but since the pre-written memory is `MaybeUninit`,
// that copy of `T` memory is only valid when status(ready) is confirmed,
// and the original `T` memory becomes directly invalid (by `forget`), completing ownership transfer.
// Therefore, this pre-write won't cause `T` to be dropped twice or not dropped at all
unsafe { self.write(&val) };
loop {
// store fence, confirm write, clear waiting state to facilitate waking
if status.try_setup_ready_release() {// weak cas
forget(val); // ownership transferred
self.try_wake_after_ready(&status);// check for waking
return Ok(());
}
if status.is_closed() {
return Err(val);
}
}
}
}
impl<T> Sender<T> {
pub fn send(self, val: T) -> Result<(), T> {...}
}
As shown above, the sender can only send once by consuming self, so in the send method, I adopted a pre-write strategy, which results in two memory regions: the pre-written value and the original value, which are actually the same value.
According to the uniqueness constraint of ownership, only one valid data can exist in both memory regions at the same time, and the other becomes "ghost data": after a successful CAS, ownership moves from the original value to the pre-written value (guaranteed by the ready flag), and the original value needs forget; otherwise, ownership remains with the original value, and the MaybeUninit in the pre-write region is still considered invalid data.
Therefore, regardless of whether the CAS succeeds or not, there is only one copy of ownership. The difference is that after success, the data will move, but this does not affect the correctness of resource deallocation.
Now the problem is, when I tried to use Copilot (GPT-5.2-Codex) to review my code, it pointed out a potential resource leak safety issue: if the CAS fails and the state becomes closed, then the original value is returned, but the copy of T in the pre-written value will never be dropped. No matter how I explain it to the AI, it insists that "although this is neither a double-free nor use-after-free, it is a resource leak".
I would like to know, does this pre-write strategy really have a resource leak problem?
11 posts - 5 participants
🏷️ Rust_feed