Skip to content

Commit 49e9bfd

Browse files
authored
Auto merge of #36104 - KiChjang:issue-35847, r=brson
Fix illegal instruction caused by overflow in channel cloning Fixes #35847. r? @alexcrichton
2 parents d748fa6 + 899c289 commit 49e9bfd

File tree

2 files changed

+24
-4
lines changed

2 files changed

+24
-4
lines changed

src/libstd/sync/mpsc/shared.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
pub use self::Failure::*;
2222

2323
use core::cmp;
24+
use core::intrinsics::abort;
2425
use core::isize;
2526

2627
use sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering};
@@ -34,6 +35,7 @@ use time::Instant;
3435

3536
const DISCONNECTED: isize = isize::MIN;
3637
const FUDGE: isize = 1024;
38+
const MAX_REFCOUNT: usize = (isize::MAX) as usize;
3739
#[cfg(test)]
3840
const MAX_STEALS: isize = 5;
3941
#[cfg(not(test))]
@@ -46,7 +48,7 @@ pub struct Packet<T> {
4648
to_wake: AtomicUsize, // SignalToken for wake up
4749

4850
// The number of channels which are currently using this packet.
49-
channels: AtomicIsize,
51+
channels: AtomicUsize,
5052

5153
// See the discussion in Port::drop and the channel send methods for what
5254
// these are used for
@@ -72,7 +74,7 @@ impl<T> Packet<T> {
7274
cnt: AtomicIsize::new(0),
7375
steals: 0,
7476
to_wake: AtomicUsize::new(0),
75-
channels: AtomicIsize::new(2),
77+
channels: AtomicUsize::new(2),
7678
port_dropped: AtomicBool::new(false),
7779
sender_drain: AtomicIsize::new(0),
7880
select_lock: Mutex::new(()),
@@ -340,7 +342,14 @@ impl<T> Packet<T> {
340342
// Prepares this shared packet for a channel clone, essentially just bumping
341343
// a refcount.
342344
pub fn clone_chan(&mut self) {
343-
self.channels.fetch_add(1, Ordering::SeqCst);
345+
let old_count = self.channels.fetch_add(1, Ordering::SeqCst);
346+
347+
// See comments on Arc::clone() on why we do this (for `mem::forget`).
348+
if old_count > MAX_REFCOUNT {
349+
unsafe {
350+
abort();
351+
}
352+
}
344353
}
345354

346355
// Decrement the reference count on a channel. This is called whenever a

src/libstd/sync/mpsc/sync.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
pub use self::Failure::*;
3737
use self::Blocker::*;
3838

39+
use core::intrinsics::abort;
40+
use core::isize;
3941
use core::mem;
4042
use core::ptr;
4143

@@ -45,6 +47,8 @@ use sync::mpsc::select::StartResult::{self, Installed, Abort};
4547
use sync::{Mutex, MutexGuard};
4648
use time::Instant;
4749

50+
const MAX_REFCOUNT: usize = (isize::MAX) as usize;
51+
4852
pub struct Packet<T> {
4953
/// Only field outside of the mutex. Just done for kicks, but mainly because
5054
/// the other shared channel already had the code implemented
@@ -350,7 +354,14 @@ impl<T> Packet<T> {
350354
// Prepares this shared packet for a channel clone, essentially just bumping
351355
// a refcount.
352356
pub fn clone_chan(&self) {
353-
self.channels.fetch_add(1, Ordering::SeqCst);
357+
let old_count = self.channels.fetch_add(1, Ordering::SeqCst);
358+
359+
// See comments on Arc::clone() on why we do this (for `mem::forget`).
360+
if old_count > MAX_REFCOUNT {
361+
unsafe {
362+
abort();
363+
}
364+
}
354365
}
355366

356367
pub fn drop_chan(&self) {

0 commit comments

Comments
 (0)