Different `waker_vtable` addresses for same type
use futures::task::ArcWake;
struct Temp;
impl ArcWake for Temp {
fn wake_by_ref(arc_self: &std::sync::Arc<Self>) {
let _ = arc_self;
}
}
fn main() {
let temp = std::sync::Arc::new(Temp);
let waker = futures::task::waker_ref(&temp);
println!("{waker:?} {:?}", waker.clone());
futures::executor::block_on(async {});
}
Sometimes (more often than not, in my experience), when running in --release mode, vtable addresses don't match:
WakerRef { waker: ManuallyDrop { value: Waker { data: 0x5654d35e5b90, vtable: 0x5654d2ad62b8 } }, _marker: PhantomData<&()> } Waker { data: 0x5654d35e5b90, vtable: 0x5654d2ad6308 }
Why this matters: this leads to AtomicWaker and alike to clone (or, worse, wake) on each poll because of how Waker::will_wake compares Wakers. Example: https://github.com/sdroege/async-tungstenite/issues/133
Is this a compiler bug? If yes, can we do something to mitigate it?
Same issue as https://github.com/rust-lang/futures-rs/pull/2829#issuecomment-1962863389 / https://github.com/rust-lang/rust/pull/121622#issuecomment-1975888092?
yes, seems to be the same issue
#[inline(always)] on clone_arc_raw has some positive effect on the situation sometimes (ref_wake_same passes?)
Quoting myself from
[...] this sounds like a bug in the code doing the comparison. If multiple codegen units are involved, it's not guaranteed that the vtable is always the same for the same object.
That's why e.g. https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.ptr_eq exists.
Resolved by https://github.com/rust-lang/futures-rs/pull/2865