From 899c2891e6be24100db723f2b5464969bcebe0f0 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Sun, 28 Aug 2016 15:48:56 -0700 Subject: [PATCH] Fix illegal instruction caused by overflow in channel cloning --- src/libstd/sync/mpsc/shared.rs | 15 ++++++++++++--- src/libstd/sync/mpsc/sync.rs | 13 ++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index baa4db7e5c0fa..2a9618251ff52 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -21,6 +21,7 @@ pub use self::Failure::*; use core::cmp; +use core::intrinsics::abort; use core::isize; use sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering}; @@ -34,6 +35,7 @@ use time::Instant; const DISCONNECTED: isize = isize::MIN; const FUDGE: isize = 1024; +const MAX_REFCOUNT: usize = (isize::MAX) as usize; #[cfg(test)] const MAX_STEALS: isize = 5; #[cfg(not(test))] @@ -46,7 +48,7 @@ pub struct Packet { to_wake: AtomicUsize, // SignalToken for wake up // The number of channels which are currently using this packet. - channels: AtomicIsize, + channels: AtomicUsize, // See the discussion in Port::drop and the channel send methods for what // these are used for @@ -72,7 +74,7 @@ impl Packet { cnt: AtomicIsize::new(0), steals: 0, to_wake: AtomicUsize::new(0), - channels: AtomicIsize::new(2), + channels: AtomicUsize::new(2), port_dropped: AtomicBool::new(false), sender_drain: AtomicIsize::new(0), select_lock: Mutex::new(()), @@ -340,7 +342,14 @@ impl Packet { // Prepares this shared packet for a channel clone, essentially just bumping // a refcount. pub fn clone_chan(&mut self) { - self.channels.fetch_add(1, Ordering::SeqCst); + let old_count = self.channels.fetch_add(1, Ordering::SeqCst); + + // See comments on Arc::clone() on why we do this (for `mem::forget`). + if old_count > MAX_REFCOUNT { + unsafe { + abort(); + } + } } // Decrement the reference count on a channel. This is called whenever a diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index 9985daaba8f69..1d16e002a2bef 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -36,6 +36,8 @@ pub use self::Failure::*; use self::Blocker::*; +use core::intrinsics::abort; +use core::isize; use core::mem; use core::ptr; @@ -45,6 +47,8 @@ use sync::mpsc::select::StartResult::{self, Installed, Abort}; use sync::{Mutex, MutexGuard}; use time::Instant; +const MAX_REFCOUNT: usize = (isize::MAX) as usize; + pub struct Packet { /// Only field outside of the mutex. Just done for kicks, but mainly because /// the other shared channel already had the code implemented @@ -350,7 +354,14 @@ impl Packet { // Prepares this shared packet for a channel clone, essentially just bumping // a refcount. pub fn clone_chan(&self) { - self.channels.fetch_add(1, Ordering::SeqCst); + let old_count = self.channels.fetch_add(1, Ordering::SeqCst); + + // See comments on Arc::clone() on why we do this (for `mem::forget`). + if old_count > MAX_REFCOUNT { + unsafe { + abort(); + } + } } pub fn drop_chan(&self) {