diff options
| author | bors <bors@rust-lang.org> | 2016-09-03 11:24:01 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-09-03 11:24:01 -0700 |
| commit | 49e9bfdbf24d5cb3cb2b3b7c103fded4682d88cc (patch) | |
| tree | d127376c1be4101e36b189ee6016a940d27b8bf8 /src/libstd | |
| parent | d748fa6ecccf6f5b4c7ae4abee0a2d206b165de2 (diff) | |
| parent | 899c2891e6be24100db723f2b5464969bcebe0f0 (diff) | |
| download | rust-49e9bfdbf24d5cb3cb2b3b7c103fded4682d88cc.tar.gz rust-49e9bfdbf24d5cb3cb2b3b7c103fded4682d88cc.zip | |
Auto merge of #36104 - KiChjang:issue-35847, r=brson
Fix illegal instruction caused by overflow in channel cloning Fixes #35847. r? @alexcrichton
Diffstat (limited to 'src/libstd')
| -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) { |
