Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix illegal instruction caused by overflow in channel cloning #36104

Merged
merged 1 commit into from
Sep 3, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/libstd/sync/mpsc/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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))]
Expand All @@ -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
Expand All @@ -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(()),
Expand Down Expand Up @@ -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
Expand Down
13 changes: 12 additions & 1 deletion src/libstd/sync/mpsc/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
pub use self::Failure::*;
use self::Blocker::*;

use core::intrinsics::abort;
use core::isize;
use core::mem;
use core::ptr;

Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand Down