Skip to content

Commit bd3fb81

Browse files
committed
auto merge of #13934 : huonw/rust/transmute-mut, r=alexcrichton
Turning a `&T` into an `&mut T` is 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`.) cc #13933
2 parents 7583544 + edd9bad commit bd3fb81

File tree

8 files changed

+74
-46
lines changed

8 files changed

+74
-46
lines changed

src/libarena/lib.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
extern crate collections;
2828

29-
use std::cast::{transmute, transmute_mut, transmute_mut_lifetime};
29+
use std::cast::{transmute, transmute_mut_lifetime};
3030
use std::cast;
3131
use std::cell::{Cell, RefCell};
3232
use std::mem;
@@ -281,8 +281,8 @@ impl Arena {
281281
#[inline]
282282
pub fn alloc<'a, T>(&'a self, op: || -> T) -> &'a T {
283283
unsafe {
284-
// FIXME: Borrow check
285-
let this = transmute_mut(self);
284+
// FIXME #13933: Remove/justify all `&T` to `&mut T` transmutes
285+
let this: &mut Arena = transmute::<&_, &mut _>(self);
286286
if intrinsics::needs_drop::<T>() {
287287
this.alloc_noncopy(op)
288288
} else {
@@ -438,7 +438,8 @@ impl<T> TypedArena<T> {
438438
#[inline]
439439
pub fn alloc<'a>(&'a self, object: T) -> &'a T {
440440
unsafe {
441-
let this = cast::transmute_mut(self);
441+
// FIXME #13933: Remove/justify all `&T` to `&mut T` transmutes
442+
let this: &mut TypedArena<T> = cast::transmute::<&_, &mut _>(self);
442443
if this.ptr == this.end {
443444
this.grow()
444445
}

src/libnative/io/file_win32.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ impl rtio::RtioFileStream for FileDesc {
174174
fn tell(&self) -> Result<u64, IoError> {
175175
// This transmute is fine because our seek implementation doesn't
176176
// actually use the mutable self at all.
177-
unsafe { cast::transmute_mut(self).seek(0, io::SeekCur) }
177+
// FIXME #13933: Remove/justify all `&T` to `&mut T` transmutes
178+
unsafe { cast::transmute::<&_, &mut FileDesc>(self).seek(0, io::SeekCur) }
178179
}
179180

180181
fn fsync(&mut self) -> Result<(), IoError> {

src/librustuv/file.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,8 @@ impl rtio::RtioFileStream for FileWatcher {
445445
fn tell(&self) -> Result<u64, IoError> {
446446
use libc::SEEK_CUR;
447447
// this is temporary
448-
let self_ = unsafe { cast::transmute_mut(self) };
448+
// FIXME #13933: Remove/justify all `&T` to `&mut T` transmutes
449+
let self_ = unsafe { cast::transmute::<&_, &mut FileWatcher>(self) };
449450
self_.seek_common(0, SEEK_CUR)
450451
}
451452
fn fsync(&mut self) -> Result<(), IoError> {

src/libstd/cast.rs

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub unsafe fn transmute<L, G>(thing: L) -> G {
6060

6161
/// Coerce an immutable reference to be mutable.
6262
#[inline]
63+
#[deprecated="casting &T to &mut T is undefined behaviour: use Cell<T>, RefCell<T> or Unsafe<T>"]
6364
pub unsafe fn transmute_mut<'a,T>(ptr: &'a T) -> &'a mut T { transmute(ptr) }
6465

6566
/// Coerce a reference to have an arbitrary associated lifetime.

src/libstd/comm/mod.rs

+49-29
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,6 @@
271271
// And now that you've seen all the races that I found and attempted to fix,
272272
// here's the code for you to find some more!
273273

274-
use cast;
275274
use cell::Cell;
276275
use clone::Clone;
277276
use iter::Iterator;
@@ -284,6 +283,7 @@ use result::{Ok, Err, Result};
284283
use rt::local::Local;
285284
use rt::task::{Task, BlockedTask};
286285
use sync::arc::UnsafeArc;
286+
use ty::Unsafe;
287287

288288
pub use comm::select::{Select, Handle};
289289

@@ -325,7 +325,7 @@ static RESCHED_FREQ: int = 256;
325325
/// The receiving-half of Rust's channel type. This half can only be owned by
326326
/// one task
327327
pub struct Receiver<T> {
328-
inner: Flavor<T>,
328+
inner: Unsafe<Flavor<T>>,
329329
receives: Cell<uint>,
330330
// can't share in an arc
331331
marker: marker::NoShare,
@@ -341,7 +341,7 @@ pub struct Messages<'a, T> {
341341
/// The sending-half of Rust's asynchronous channel type. This half can only be
342342
/// owned by one task, but it can be cloned to send to other tasks.
343343
pub struct Sender<T> {
344-
inner: Flavor<T>,
344+
inner: Unsafe<Flavor<T>>,
345345
sends: Cell<uint>,
346346
// can't share in an arc
347347
marker: marker::NoShare,
@@ -390,6 +390,27 @@ enum Flavor<T> {
390390
Sync(UnsafeArc<sync::Packet<T>>),
391391
}
392392

393+
#[doc(hidden)]
394+
trait UnsafeFlavor<T> {
395+
fn inner_unsafe<'a>(&'a self) -> &'a Unsafe<Flavor<T>>;
396+
unsafe fn mut_inner<'a>(&'a self) -> &'a mut Flavor<T> {
397+
&mut *self.inner_unsafe().get()
398+
}
399+
unsafe fn inner<'a>(&'a self) -> &'a Flavor<T> {
400+
&*self.inner_unsafe().get()
401+
}
402+
}
403+
impl<T> UnsafeFlavor<T> for Sender<T> {
404+
fn inner_unsafe<'a>(&'a self) -> &'a Unsafe<Flavor<T>> {
405+
&self.inner
406+
}
407+
}
408+
impl<T> UnsafeFlavor<T> for Receiver<T> {
409+
fn inner_unsafe<'a>(&'a self) -> &'a Unsafe<Flavor<T>> {
410+
&self.inner
411+
}
412+
}
413+
393414
/// Creates a new asynchronous channel, returning the sender/receiver halves.
394415
///
395416
/// All data sent on the sender will become available on the receiver, and no
@@ -458,7 +479,7 @@ pub fn sync_channel<T: Send>(bound: uint) -> (SyncSender<T>, Receiver<T>) {
458479

459480
impl<T: Send> Sender<T> {
460481
fn new(inner: Flavor<T>) -> Sender<T> {
461-
Sender { inner: inner, sends: Cell::new(0), marker: marker::NoShare }
482+
Sender { inner: Unsafe::new(inner), sends: Cell::new(0), marker: marker::NoShare }
462483
}
463484

464485
/// Sends a value along this channel to be received by the corresponding
@@ -532,7 +553,7 @@ impl<T: Send> Sender<T> {
532553
task.map(|t| t.maybe_yield());
533554
}
534555

535-
let (new_inner, ret) = match self.inner {
556+
let (new_inner, ret) = match *unsafe { self.inner() } {
536557
Oneshot(ref p) => {
537558
let p = p.get();
538559
unsafe {
@@ -564,16 +585,16 @@ impl<T: Send> Sender<T> {
564585
};
565586

566587
unsafe {
567-
let mut tmp = Sender::new(Stream(new_inner));
568-
mem::swap(&mut cast::transmute_mut(self).inner, &mut tmp.inner);
588+
let tmp = Sender::new(Stream(new_inner));
589+
mem::swap(self.mut_inner(), tmp.mut_inner());
569590
}
570591
return ret;
571592
}
572593
}
573594

574595
impl<T: Send> Clone for Sender<T> {
575596
fn clone(&self) -> Sender<T> {
576-
let (packet, sleeper) = match self.inner {
597+
let (packet, sleeper) = match *unsafe { self.inner() } {
577598
Oneshot(ref p) => {
578599
let (a, b) = UnsafeArc::new2(shared::Packet::new());
579600
match unsafe { (*p.get()).upgrade(Receiver::new(Shared(a))) } {
@@ -598,8 +619,8 @@ impl<T: Send> Clone for Sender<T> {
598619
unsafe {
599620
(*packet.get()).inherit_blocker(sleeper);
600621

601-
let mut tmp = Sender::new(Shared(packet.clone()));
602-
mem::swap(&mut cast::transmute_mut(self).inner, &mut tmp.inner);
622+
let tmp = Sender::new(Shared(packet.clone()));
623+
mem::swap(self.mut_inner(), tmp.mut_inner());
603624
}
604625
Sender::new(Shared(packet))
605626
}
@@ -608,7 +629,7 @@ impl<T: Send> Clone for Sender<T> {
608629
#[unsafe_destructor]
609630
impl<T: Send> Drop for Sender<T> {
610631
fn drop(&mut self) {
611-
match self.inner {
632+
match *unsafe { self.mut_inner() } {
612633
Oneshot(ref mut p) => unsafe { (*p.get()).drop_chan(); },
613634
Stream(ref mut p) => unsafe { (*p.get()).drop_chan(); },
614635
Shared(ref mut p) => unsafe { (*p.get()).drop_chan(); },
@@ -705,7 +726,7 @@ impl<T: Send> Drop for SyncSender<T> {
705726

706727
impl<T: Send> Receiver<T> {
707728
fn new(inner: Flavor<T>) -> Receiver<T> {
708-
Receiver { inner: inner, receives: Cell::new(0), marker: marker::NoShare }
729+
Receiver { inner: Unsafe::new(inner), receives: Cell::new(0), marker: marker::NoShare }
709730
}
710731

711732
/// Blocks waiting for a value on this receiver
@@ -757,7 +778,7 @@ impl<T: Send> Receiver<T> {
757778
}
758779

759780
loop {
760-
let mut new_port = match self.inner {
781+
let new_port = match *unsafe { self.inner() } {
761782
Oneshot(ref p) => {
762783
match unsafe { (*p.get()).try_recv() } {
763784
Ok(t) => return Ok(t),
@@ -790,8 +811,8 @@ impl<T: Send> Receiver<T> {
790811
}
791812
};
792813
unsafe {
793-
mem::swap(&mut cast::transmute_mut(self).inner,
794-
&mut new_port.inner);
814+
mem::swap(self.mut_inner(),
815+
new_port.mut_inner());
795816
}
796817
}
797818
}
@@ -810,7 +831,7 @@ impl<T: Send> Receiver<T> {
810831
/// the value found on the receiver is returned.
811832
pub fn recv_opt(&self) -> Result<T, ()> {
812833
loop {
813-
let mut new_port = match self.inner {
834+
let new_port = match *unsafe { self.inner() } {
814835
Oneshot(ref p) => {
815836
match unsafe { (*p.get()).recv() } {
816837
Ok(t) => return Ok(t),
@@ -837,8 +858,7 @@ impl<T: Send> Receiver<T> {
837858
Sync(ref p) => return unsafe { (*p.get()).recv() }
838859
};
839860
unsafe {
840-
mem::swap(&mut cast::transmute_mut(self).inner,
841-
&mut new_port.inner);
861+
mem::swap(self.mut_inner(), new_port.mut_inner());
842862
}
843863
}
844864
}
@@ -853,7 +873,7 @@ impl<T: Send> Receiver<T> {
853873
impl<T: Send> select::Packet for Receiver<T> {
854874
fn can_recv(&self) -> bool {
855875
loop {
856-
let mut new_port = match self.inner {
876+
let new_port = match *unsafe { self.inner() } {
857877
Oneshot(ref p) => {
858878
match unsafe { (*p.get()).can_recv() } {
859879
Ok(ret) => return ret,
@@ -874,15 +894,15 @@ impl<T: Send> select::Packet for Receiver<T> {
874894
}
875895
};
876896
unsafe {
877-
mem::swap(&mut cast::transmute_mut(self).inner,
878-
&mut new_port.inner);
897+
mem::swap(self.mut_inner(),
898+
new_port.mut_inner());
879899
}
880900
}
881901
}
882902

883903
fn start_selection(&self, mut task: BlockedTask) -> Result<(), BlockedTask>{
884904
loop {
885-
let (t, mut new_port) = match self.inner {
905+
let (t, new_port) = match *unsafe { self.inner() } {
886906
Oneshot(ref p) => {
887907
match unsafe { (*p.get()).start_selection(task) } {
888908
oneshot::SelSuccess => return Ok(()),
@@ -906,16 +926,16 @@ impl<T: Send> select::Packet for Receiver<T> {
906926
};
907927
task = t;
908928
unsafe {
909-
mem::swap(&mut cast::transmute_mut(self).inner,
910-
&mut new_port.inner);
929+
mem::swap(self.mut_inner(),
930+
new_port.mut_inner());
911931
}
912932
}
913933
}
914934

915935
fn abort_selection(&self) -> bool {
916936
let mut was_upgrade = false;
917937
loop {
918-
let result = match self.inner {
938+
let result = match *unsafe { self.inner() } {
919939
Oneshot(ref p) => unsafe { (*p.get()).abort_selection() },
920940
Stream(ref p) => unsafe {
921941
(*p.get()).abort_selection(was_upgrade)
@@ -927,11 +947,11 @@ impl<T: Send> select::Packet for Receiver<T> {
927947
(*p.get()).abort_selection()
928948
},
929949
};
930-
let mut new_port = match result { Ok(b) => return b, Err(p) => p };
950+
let new_port = match result { Ok(b) => return b, Err(p) => p };
931951
was_upgrade = true;
932952
unsafe {
933-
mem::swap(&mut cast::transmute_mut(self).inner,
934-
&mut new_port.inner);
953+
mem::swap(self.mut_inner(),
954+
new_port.mut_inner());
935955
}
936956
}
937957
}
@@ -944,7 +964,7 @@ impl<'a, T: Send> Iterator<T> for Messages<'a, T> {
944964
#[unsafe_destructor]
945965
impl<T: Send> Drop for Receiver<T> {
946966
fn drop(&mut self) {
947-
match self.inner {
967+
match *unsafe { self.mut_inner() } {
948968
Oneshot(ref mut p) => unsafe { (*p.get()).drop_port(); },
949969
Stream(ref mut p) => unsafe { (*p.get()).drop_port(); },
950970
Shared(ref mut p) => unsafe { (*p.get()).drop_port(); },

src/libstd/local_data.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,11 @@ pub fn get_mut<T: 'static, U>(key: Key<T>, f: |Option<&mut T>| -> U) -> U {
196196
match x {
197197
None => f(None),
198198
// We're violating a lot of compiler guarantees with this
199-
// invocation of `transmute_mut`, but we're doing runtime checks to
199+
// invocation of `transmute`, but we're doing runtime checks to
200200
// ensure that it's always valid (only one at a time).
201201
//
202202
// there is no need to be upset!
203-
Some(x) => { f(Some(unsafe { cast::transmute_mut(x) })) }
203+
Some(x) => { f(Some(unsafe { cast::transmute::<&_, &mut _>(x) })) }
204204
}
205205
})
206206
}

src/libstd/slice.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -1739,15 +1739,19 @@ impl<'a,T> MutableVector<'a, T> for &'a mut [T] {
17391739
if self.len() == 0 { return None; }
17401740
unsafe {
17411741
let s: &mut Slice<T> = transmute(self);
1742-
Some(cast::transmute_mut(&*raw::shift_ptr(s)))
1742+
// FIXME #13933: this `&` -> `&mut` cast is a little
1743+
// dubious
1744+
Some(&mut *(raw::shift_ptr(s) as *mut _))
17431745
}
17441746
}
17451747

17461748
fn mut_pop_ref(&mut self) -> Option<&'a mut T> {
17471749
if self.len() == 0 { return None; }
17481750
unsafe {
17491751
let s: &mut Slice<T> = transmute(self);
1750-
Some(cast::transmute_mut(&*raw::pop_ptr(s)))
1752+
// FIXME #13933: this `&` -> `&mut` cast is a little
1753+
// dubious
1754+
Some(&mut *(raw::pop_ptr(s) as *mut _))
17511755
}
17521756
}
17531757

@@ -3108,23 +3112,23 @@ mod tests {
31083112
#[should_fail]
31093113
fn test_from_elem_fail() {
31103114
use cast;
3115+
use cell::Cell;
31113116
use rc::Rc;
31123117

31133118
struct S {
3114-
f: int,
3119+
f: Cell<int>,
31153120
boxes: (~int, Rc<int>)
31163121
}
31173122

31183123
impl Clone for S {
31193124
fn clone(&self) -> S {
3120-
let s = unsafe { cast::transmute_mut(self) };
3121-
s.f += 1;
3122-
if s.f == 10 { fail!() }
3123-
S { f: s.f, boxes: s.boxes.clone() }
3125+
self.f.set(self.f.get() + 1);
3126+
if self.f.get() == 10 { fail!() }
3127+
S { f: self.f, boxes: self.boxes.clone() }
31243128
}
31253129
}
31263130

3127-
let s = S { f: 0, boxes: (box 0, Rc::new(0)) };
3131+
let s = S { f: Cell::new(0), boxes: (box 0, Rc::new(0)) };
31283132
let _ = Vec::from_elem(100, s);
31293133
}
31303134

src/libsync/arc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ impl<T: Send + Share + Clone> Arc<T> {
148148
// reference count is guaranteed to be 1 at this point, and we required
149149
// the Arc itself to be `mut`, so we're returning the only possible
150150
// reference to the inner data.
151-
unsafe { cast::transmute_mut(self.deref()) }
151+
unsafe { cast::transmute::<&_, &mut _>(self.deref()) }
152152
}
153153
}
154154

0 commit comments

Comments
 (0)