Skip to content

Commit 2674a16

Browse files
committed
auto merge of #13211 : csherratt/rust/arc_fix, r=alexcrichton
This is a fix for #13210. fetch_sub returns the old value of the atomic variable, not the new one.
2 parents 90085a1 + 9fc45c1 commit 2674a16

File tree

1 file changed

+38
-4
lines changed

1 file changed

+38
-4
lines changed

src/libsync/arc.rs

+38-4
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ impl<T: Share + Send> Drop for Arc<T> {
165165
// Because `fetch_sub` is already atomic, we do not need to synchronize
166166
// with other threads unless we are going to delete the object. This
167167
// same logic applies to the below `fetch_sub` to the `weak` count.
168-
if self.inner().strong.fetch_sub(1, atomics::Release) != 0 { return }
168+
if self.inner().strong.fetch_sub(1, atomics::Release) != 1 { return }
169169

170170
// This fence is needed to prevent reordering of use of the data and
171171
// deletion of the data. Because it is marked `Release`, the
@@ -190,7 +190,7 @@ impl<T: Share + Send> Drop for Arc<T> {
190190
// allocation itself (there may still be weak pointers lying around).
191191
unsafe { drop(ptr::read(&self.inner().data)); }
192192

193-
if self.inner().weak.fetch_sub(1, atomics::Release) == 0 {
193+
if self.inner().weak.fetch_sub(1, atomics::Release) == 1 {
194194
atomics::fence(atomics::Acquire);
195195
unsafe { global_heap::exchange_free(self.x as *u8) }
196196
}
@@ -240,7 +240,7 @@ impl<T: Share + Send> Drop for Weak<T> {
240240
// If we find out that we were the last weak pointer, then its time to
241241
// deallocate the data entirely. See the discussion in Arc::drop() about
242242
// the memory orderings
243-
if self.inner().weak.fetch_sub(1, atomics::Release) == 0 {
243+
if self.inner().weak.fetch_sub(1, atomics::Release) == 1 {
244244
atomics::fence(atomics::Acquire);
245245
unsafe { global_heap::exchange_free(self.x as *u8) }
246246
}
@@ -251,9 +251,24 @@ impl<T: Share + Send> Drop for Weak<T> {
251251
#[allow(experimental)]
252252
mod tests {
253253
use super::{Arc, Weak};
254+
use std::sync::atomics;
255+
use std::task;
254256
use Mutex;
255257

256-
use std::task;
258+
struct Canary(*mut atomics::AtomicUint);
259+
260+
impl Drop for Canary
261+
{
262+
fn drop(&mut self) {
263+
unsafe {
264+
match *self {
265+
Canary(c) => {
266+
(*c).fetch_add(1, atomics::SeqCst);
267+
}
268+
}
269+
}
270+
}
271+
}
257272

258273
#[test]
259274
fn manually_share_arc() {
@@ -349,4 +364,23 @@ mod tests {
349364

350365
// hopefully we don't double-free (or leak)...
351366
}
367+
368+
#[test]
369+
fn drop_arc() {
370+
let mut canary = atomics::AtomicUint::new(0);
371+
let x = Arc::new(Canary(&mut canary as *mut atomics::AtomicUint));
372+
drop(x);
373+
assert!(canary.load(atomics::Acquire) == 1);
374+
}
375+
376+
#[test]
377+
fn drop_arc_weak() {
378+
let mut canary = atomics::AtomicUint::new(0);
379+
let arc = Arc::new(Canary(&mut canary as *mut atomics::AtomicUint));
380+
let arc_weak = arc.downgrade();
381+
assert!(canary.load(atomics::Acquire) == 0);
382+
drop(arc);
383+
assert!(canary.load(atomics::Acquire) == 1);
384+
drop(arc_weak);
385+
}
352386
}

0 commit comments

Comments
 (0)