about summary refs log tree commit diff
path: root/src/libstd/sync
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-09-03 11:24:01 -0700
committerGitHub <noreply@github.com>2016-09-03 11:24:01 -0700
commit49e9bfdbf24d5cb3cb2b3b7c103fded4682d88cc (patch)
treed127376c1be4101e36b189ee6016a940d27b8bf8 /src/libstd/sync
parentd748fa6ecccf6f5b4c7ae4abee0a2d206b165de2 (diff)
parent899c2891e6be24100db723f2b5464969bcebe0f0 (diff)
downloadrust-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/sync')
-rw-r--r--src/libstd/sync/mpsc/shared.rs15
-rw-r--r--src/libstd/sync/mpsc/sync.rs13
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) {