diff options
| author | Keith Yeung <kungfukeith11@gmail.com> | 2016-08-28 15:48:56 -0700 |
|---|---|---|
| committer | Keith Yeung <kungfukeith11@gmail.com> | 2016-08-29 10:27:59 -0700 |
| commit | 899c2891e6be24100db723f2b5464969bcebe0f0 (patch) | |
| tree | 563ba3175d542f719dc233af876a451304991729 /src/libstd/sync | |
| parent | e4791e086d671d429db864787f6b60547a28b0f5 (diff) | |
| download | rust-899c2891e6be24100db723f2b5464969bcebe0f0.tar.gz rust-899c2891e6be24100db723f2b5464969bcebe0f0.zip | |
Fix illegal instruction caused by overflow in channel cloning
Diffstat (limited to 'src/libstd/sync')
| -rw-r--r-- | src/libstd/sync/mpsc/shared.rs | 15 | ||||
| -rw-r--r-- | 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 baa4db7e5c0..2a9618251ff 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<T> { 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<T> Packet<T> { 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<T> Packet<T> { // 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 9985daaba8f..1d16e002a2b 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<T> { /// 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<T> Packet<T> { // 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) { |
