From fd0e15bbcda4b1674f22e8db5fd81a63d671c996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 20 Mar 2020 00:00:00 +0000 Subject: [PATCH] Make std::sync::Arc compatible with ThreadSanitizer The memory fences used previously in Arc implementation are not properly understood by ThreadSanitizer as synchronization primitives. This had unfortunate effect where running any non-trivial program compiled with `-Z sanitizer=thread` would result in numerous false positives. Replace acquire fences with acquire loads when using ThreadSanitizer to address the issue. --- src/liballoc/lib.rs | 1 + src/liballoc/sync.rs | 25 +++++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index ffa4176cc796..d877ac6ac5c7 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -80,6 +80,7 @@ #![feature(box_into_raw_non_null)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(cfg_sanitize)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] #![feature(const_generic_impls_guard)] diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 4a0cf2984edd..d9b54fb0b177 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -40,6 +40,23 @@ mod tests; /// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references. const MAX_REFCOUNT: usize = (isize::MAX) as usize; +#[cfg(not(sanitize = "thread"))] +macro_rules! acquire { + ($x:expr) => { + atomic::fence(Acquire) + }; +} + +// ThreadSanitizer does not support memory fences. To avoid false positive +// reports in Arc / Weak implementation use atomic loads for synchronization +// instead. +#[cfg(sanitize = "thread")] +macro_rules! acquire { + ($x:expr) => { + $x.load(Acquire) + }; +} + /// A thread-safe reference-counting pointer. 'Arc' stands for 'Atomically /// Reference Counted'. /// @@ -402,7 +419,7 @@ impl Arc { return Err(this); } - atomic::fence(Acquire); + acquire!(this.inner().strong); unsafe { let elem = ptr::read(&this.ptr.as_ref().data); @@ -739,7 +756,7 @@ impl Arc { ptr::drop_in_place(&mut self.ptr.as_mut().data); if self.inner().weak.fetch_sub(1, Release) == 1 { - atomic::fence(Acquire); + acquire!(self.inner().weak); Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } } @@ -1243,7 +1260,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc { // // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) // [2]: (https://github.com/rust-lang/rust/pull/41714) - atomic::fence(Acquire); + acquire!(self.inner().strong); unsafe { self.drop_slow(); @@ -1701,7 +1718,7 @@ impl Drop for Weak { let inner = if let Some(inner) = self.inner() { inner } else { return }; if inner.weak.fetch_sub(1, Release) == 1 { - atomic::fence(Acquire); + acquire!(inner.weak); unsafe { Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) } } }