sync::mpsc: prevent double free on Drop
This PR is fixing a regression introduced by #121646 that can lead to a double free when dropping the channel. The details of the bug can be found in the corresponding crossbeam PR https://github.com/crossbeam-rs/crossbeam/pull/1187 Signed-off-by: Petros Angelatos <petrosagg@gmail.com>
This commit is contained in:
parent
9eb6a5446a
commit
b9e2ac5c7b
2 changed files with 8 additions and 2 deletions
|
@ -569,9 +569,15 @@ impl<T> Channel<T> {
|
|||
// In that case, just wait until it gets initialized.
|
||||
while block.is_null() {
|
||||
backoff.spin_heavy();
|
||||
block = self.head.block.load(Ordering::Acquire);
|
||||
block = self.head.block.swap(ptr::null_mut(), Ordering::AcqRel);
|
||||
}
|
||||
}
|
||||
// After this point `head.block` is not modified again and it will be deallocated if it's
|
||||
// non-null. The `Drop` code of the channel, which runs after this function, also attempts
|
||||
// to deallocate `head.block` if it's non-null. Therefore this function must maintain the
|
||||
// invariant that if a deallocation of head.block is attemped then it must also be set to
|
||||
// NULL. Failing to do so will lead to the Drop code attempting a double free. For this
|
||||
// reason both reads above do an atomic swap instead of a simple atomic load.
|
||||
|
||||
unsafe {
|
||||
// Drop all messages between head and tail and deallocate the heap-allocated blocks.
|
||||
|
|
|
@ -38,7 +38,7 @@ fn main() {
|
|||
// call returns the channel state has tail.index = head.index, tail.block = NULL, and
|
||||
// head.block != NULL.
|
||||
t1.join().unwrap();
|
||||
// 6. The last sender (s1) is dropped here which also attempts to cleanup any data in the
|
||||
// 6. The last sender (s2) is dropped here which also attempts to cleanup any data in the
|
||||
// channel. It observes `tail.index = head.index` and so it doesn't attempt to cleanup any
|
||||
// messages but it also observes that `head.block != NULL` and attempts to deallocate it.
|
||||
// This is however already deallocated by `discard_all_messages`, leading to a double free.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue