Auto merge of #36104 - KiChjang:issue-35847, r=brson

Fix illegal instruction caused by overflow in channel cloning

Fixes #35847.

r? @alexcrichton
This commit is contained in:
bors 2016-09-03 11:24:01 -07:00 committed by GitHub
commit 49e9bfdbf2
2 changed files with 24 additions and 4 deletions

View File

@ -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

View File

@ -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) {