Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Don't produce temporary
&mut T
when retiring
Or: Miri saves my butt, exhibit number 19388228. Miri was complaining that accessing a reference obtained from `HazardPointer::load` after a call to `retire` for the loaded value was illegal. This should not be the case, since it's exactly what hazard pointers are intended to guard against. Following the call-chain for `Replaced::retire`, on a hunch I hovered over `self.ptr.as_mut` and saw (to my horror) that its return type was `&mut T` (not `*mut T`). This is undefined behavior, since we're trying to create a `&mut T`, which _requires_ exclusivity, while there is an active `&T` to the same referent. Even though it's immediately turned back into a `*mut T`, that's enough to trigger UB. The fix is to never create the `&mut` in the first place, and just directly get the pointer from the `NonNull`. Normally, this error would have been caught by `NonNull::as_mut` being `unsafe`. _But_, since we're calling `retire_ptr` in the same statement, and wrapped that whole call in `unsafe`, I didn't realize that there were _two_ `unsafe` calls in there, not just the one. And we weren't meeting the safety requirements of one of those calls (`as_mut`). So, I've hoisted out the method call on `ptr` to avoid this happening again in the future. The move from `as_mut` to `as_ptr` also means we no longer need `&mut` to the `NonNull` (which should have been another clue something was wrong), so the function doesn't need `mut self` (though it does still consume ownership). I'll add that `-Zmiri-track-pointer-tag=<tag from error>` would also have helped track this down (rust-lang/miri#531), but I didn't find it until after I'd found the problem. Lesson learned for next time!
- Loading branch information