Skip to content

LocalWaker drops itself when cloning #52629

Closed
@Thomasdezeeuw

Description

@Thomasdezeeuw

Running the following code:

#![feature(futures_api)]

use std::ptr::NonNull;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::task::{LocalWaker, Waker, UnsafeWake};

pub fn new_waker() -> LocalWaker {
    let waker = Box::new(MyWaker { count: AtomicUsize::new(0) });
    let ptr: *const dyn UnsafeWake = Box::into_raw(waker);
    let ptr = unsafe { NonNull::new_unchecked(ptr as *mut _) };
    unsafe { LocalWaker::new(ptr) }
}

#[derive(Debug)]
struct MyWaker {
    count: AtomicUsize,
}

unsafe impl UnsafeWake for MyWaker {
    unsafe fn clone_raw(&self) -> Waker {
        println!("clone_raw");
        let ptr: *const UnsafeWake = self;
        let ptr = NonNull::new_unchecked(ptr as *mut _);
        self.count.fetch_add(1, Ordering::SeqCst);
        Waker::new(ptr)
    }

    unsafe fn drop_raw(&self) {
        println!("drop_raw");
        if self.count.fetch_sub(1, Ordering::SeqCst) == 1 {
            // TODO: actually drop self.
        }
    }

    unsafe fn wake(&self) {
        println!("wake");
    }
}

fn main() {
    let local_waker1 = new_waker();
    let local_waker2  = local_waker1.clone();

    local_waker2.wake();

    drop(local_waker1);
    drop(local_waker2);
}

Prints the following:

clone_raw
drop_raw                     # The problem.
wake
drop_raw
drop_raw

It has an extra call to drop_raw.

I think it's because of the Clone implementation of LocalWaker:

unsafe {
        LocalWaker { inner: self.inner.as_ref().clone_raw().inner }
}

As UnsafeWake::clone_raw returns an Waker the LocalWaker code just takes the inner value. However because of this the Waker will be dropped and hence the erroneous extra call to drop_raw.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions