about summary refs log tree commit diff
path: root/src/libstd/comm
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2014-05-04 23:17:37 +1000
committerHuon Wilson <dbau.pp+github@gmail.com>2014-05-05 18:20:41 +1000
commit781ac3e777a5f47bdfaba05ee17f8b79845670b1 (patch)
tree4c79abc527b6dfdfadd39bf7fe8ac96ad05326a8 /src/libstd/comm
parentabdacecdf86b4b5a4f432560445a24e1c5f4751b (diff)
downloadrust-781ac3e777a5f47bdfaba05ee17f8b79845670b1.tar.gz
rust-781ac3e777a5f47bdfaba05ee17f8b79845670b1.zip
std: deprecate cast::transmute_mut.
Turning a `&T` into an `&mut T` carries a large risk of undefined
behaviour, and needs to be done very very carefully. Providing a
convenience function for exactly this task is a bad idea, just tempting
people into doing the wrong thing.

The right thing is to use types like `Cell`, `RefCell` or `Unsafe`.

For memory safety, Rust has that guarantee that `&mut` pointers do not
alias with any other pointer, that is, if you have a `&mut T` then that
is the only usable pointer to that `T`. This allows Rust to assume that
writes through a `&mut T` do not affect the values of any other `&` or
`&mut` references. `&` pointers have no guarantees about aliasing or
not, so it's entirely possible for the same pointer to be passed into
both arguments of a function like

    fn foo(x: &int, y: &int) { ... }

Converting either of `x` or `y` to a `&mut` pointer and modifying it
would affect the other value: invalid behaviour.

(Similarly, it's undefined behaviour to modify the value of an immutable
local, like `let x = 1;`.)

At a low-level, the *only* safe way to obtain an `&mut` out of a `&` is
using the `Unsafe` type (there are higher level wrappers around it, like
`Cell`, `RefCell`, `Mutex` etc.). The `Unsafe` type is registered with
the compiler so that it can reason a little about these `&` to `&mut`
casts, but it is still up to the user to ensure that the `&mut`s
obtained out of an `Unsafe` never alias.

(Note that *any* conversion from `&` to `&mut` can be invalid, including
a plain `transmute`, or casting `&T` -> `*T` -> `*mut T` -> `&mut T`.)

[breaking-change]
Diffstat (limited to 'src/libstd/comm')
-rw-r--r--src/libstd/comm/mod.rs19
1 files changed, 12 insertions, 7 deletions
diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs
index 92e3e82c1c5..bbe34d20f6a 100644
--- a/src/libstd/comm/mod.rs
+++ b/src/libstd/comm/mod.rs
@@ -318,6 +318,11 @@ mod stream;
 mod shared;
 mod sync;
 
+// FIXME #13933: Remove/justify all `&T` to `&mut T` transmutes
+unsafe fn transmute_mut<'a,T>(x: &'a T) -> &'a mut T {
+    cast::transmute::<&_, &mut _>(x)
+}
+
 // Use a power of 2 to allow LLVM to optimize to something that's not a
 // division, this is hit pretty regularly.
 static RESCHED_FREQ: int = 256;
@@ -565,7 +570,7 @@ impl<T: Send> Sender<T> {
 
         unsafe {
             let mut tmp = Sender::new(Stream(new_inner));
-            mem::swap(&mut cast::transmute_mut(self).inner, &mut tmp.inner);
+            mem::swap(&mut transmute_mut(self).inner, &mut tmp.inner);
         }
         return ret;
     }
@@ -599,7 +604,7 @@ impl<T: Send> Clone for Sender<T> {
             (*packet.get()).inherit_blocker(sleeper);
 
             let mut tmp = Sender::new(Shared(packet.clone()));
-            mem::swap(&mut cast::transmute_mut(self).inner, &mut tmp.inner);
+            mem::swap(&mut transmute_mut(self).inner, &mut tmp.inner);
         }
         Sender::new(Shared(packet))
     }
@@ -790,7 +795,7 @@ impl<T: Send> Receiver<T> {
                 }
             };
             unsafe {
-                mem::swap(&mut cast::transmute_mut(self).inner,
+                mem::swap(&mut transmute_mut(self).inner,
                           &mut new_port.inner);
             }
         }
@@ -837,7 +842,7 @@ impl<T: Send> Receiver<T> {
                 Sync(ref p) => return unsafe { (*p.get()).recv() }
             };
             unsafe {
-                mem::swap(&mut cast::transmute_mut(self).inner,
+                mem::swap(&mut transmute_mut(self).inner,
                           &mut new_port.inner);
             }
         }
@@ -874,7 +879,7 @@ impl<T: Send> select::Packet for Receiver<T> {
                 }
             };
             unsafe {
-                mem::swap(&mut cast::transmute_mut(self).inner,
+                mem::swap(&mut transmute_mut(self).inner,
                           &mut new_port.inner);
             }
         }
@@ -906,7 +911,7 @@ impl<T: Send> select::Packet for Receiver<T> {
             };
             task = t;
             unsafe {
-                mem::swap(&mut cast::transmute_mut(self).inner,
+                mem::swap(&mut transmute_mut(self).inner,
                           &mut new_port.inner);
             }
         }
@@ -930,7 +935,7 @@ impl<T: Send> select::Packet for Receiver<T> {
             let mut new_port = match result { Ok(b) => return b, Err(p) => p };
             was_upgrade = true;
             unsafe {
-                mem::swap(&mut cast::transmute_mut(self).inner,
+                mem::swap(&mut transmute_mut(self).inner,
                           &mut new_port.inner);
             }
         }