From 3d03f7541e37fe4728149f6466d4c8aba51d7ec0 Mon Sep 17 00:00:00 2001 From: ubsan Date: Fri, 1 Jul 2016 23:33:44 -0700 Subject: [PATCH 01/14] Add more docs - mostly warnings - to std::mem::transmute --- src/libcore/intrinsics.rs | 99 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index edb965c1962e3..1b52ea33d375a 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -278,18 +278,109 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. pub fn forget(_: T) -> (); - /// Unsafely transforms a value of one type into a value of another type. + /// Bitcasts a value of one type to another. Both types must have the same + /// size. /// - /// Both types must have the same size. + /// `transmute::(t)` is semantically equivalent to the following: + /// + /// ``` + /// fn transmute(t: T) -> U { + /// let u: U = std::mem::uninitialized(); + /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, + /// &mut u as *mut U as *mut u8, + /// std::mem::size_of::()); + /// std::mem::forget(t); + /// u + /// } + /// ``` + /// + /// `transmute` is incredibly unsafe. There are an incredible number of ways + /// to cause undefined behavior with this function. `transmute` should be + /// the absolute last resort. + /// + /// The following is more complete documentation. Read it before using + /// `transmute`: + /// [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) /// /// # Examples /// /// ``` /// use std::mem; /// - /// let array: &[u8] = unsafe { mem::transmute("Rust") }; - /// assert_eq!(array, [82, 117, 115, 116]); + /// let slice: &[u8] = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // this is not a good way to do this. + /// // use .as_bytes() + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // Or, just use a byte string + /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// ``` + /// + /// There are very few good cases for `transmute`. Most can be achieved + /// through other means. Some commone uses, and the less unsafe way, are as + /// follows: + /// + /// ``` + /// // Turning a *mut T into an &mut T + /// let ptr: *mut i32 = &mut 0; + /// let reF_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr); + /// let ref_casted = &mut *ptr; + /// ``` + /// /// ``` + /// // Turning an &mut T into an &mut U + /// let ptr = &mut 0; + /// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr); + /// // There is a better way, using `as` and reborrowing: + /// let val_casts = &mut *(ptr as *mut T as *mut U); + /// ``` + /// + /// ``` + /// // Copying an `&mut T` to reslice: + /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// let slice2 = std::mem::transmute::<&mut [T], &mut [T]>(slice); + /// (slice[0..index], slice2[index..len]) + /// } + /// // or: + /// fn split_at_mut_casts(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! + /// (slice[0..index], slice2[index..len]) + /// } + /// ``` + /// + /// There are valid uses of transmute. + /// + /// ``` + /// // getting the bitpattern of a floating point type + /// let x = std::mem::transmute::(0.0/0.0) + /// + /// // turning a pointer into a function pointer + /// // in file.c: `int foo(void) { ... }` + /// let handle: *mut libc::c_void = libc::dlopen( + /// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY); + /// let foo: *mut libc::c_void = libc::dlsym( + /// handle, + /// b"foo\0".as_ptr() as *const libc::c_char); + /// let foo = std::mem::transmute::<*mut libc::c_void, + /// extern fn() -> libc::c_int>(foo); + /// println!("{}", foo()); + /// + /// // extending an invariant lifetime; this is advanced, very unsafe rust + /// struct T<'a>(&'a i32); + /// let value = 0; + /// let t = T::new(&value); + /// let ptr = &mut t; + /// let ptr_extended = std::mem::transmute::<&mut T, &mut T<'static>>(ptr); + /// ``` + /// + /// But these are few and far between. #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; From 233b45f0d714e0fd48b297a531bc57138d524a3a Mon Sep 17 00:00:00 2001 From: ubsan Date: Fri, 1 Jul 2016 23:57:10 -0700 Subject: [PATCH 02/14] Fix up some things which scott mentioned --- src/libcore/intrinsics.rs | 81 ++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1b52ea33d375a..c7ea5e9da640b 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -278,65 +278,74 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. pub fn forget(_: T) -> (); - /// Bitcasts a value of one type to another. Both types must have the same - /// size. + /// Reinterprets the bits of a value of one type as another type. Both types + /// must have the same size. Neither the original, nor the result, may be an + /// invalid value, or else you'll have UB on your hands. /// /// `transmute::(t)` is semantically equivalent to the following: /// /// ``` + /// // assuming that T and U are the same size /// fn transmute(t: T) -> U { - /// let u: U = std::mem::uninitialized(); - /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, - /// &mut u as *mut U as *mut u8, - /// std::mem::size_of::()); - /// std::mem::forget(t); - /// u + /// let u: U = std::mem::uninitialized(); + /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, + /// &mut u as *mut U as *mut u8, + /// std::mem::size_of::()); + /// std::mem::forget(t); + /// u /// } /// ``` /// - /// `transmute` is incredibly unsafe. There are an incredible number of ways - /// to cause undefined behavior with this function. `transmute` should be + /// `transmute` is incredibly unsafe. There are a vast number of ways to + /// cause undefined behavior with this function. `transmute` should be /// the absolute last resort. /// /// The following is more complete documentation. Read it before using /// `transmute`: /// [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) /// - /// # Examples + /// # Alternatives + /// + /// There are very few good cases for `transmute`. Most can be achieved + /// through other means. Some more or less common uses, and a better way, + /// are as follows: /// /// ``` /// use std::mem; /// - /// let slice: &[u8] = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // this is not a good way to do this. - /// // use .as_bytes() - /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // Or, just use a byte string - /// assert_eq!(b"Rust", [82, 117, 116, 116]); - /// ``` + /// // turning a pointer into a usize + /// let ptr = &0; + /// let ptr_num_transmute = std::mem::transmute::<&i32, usize>(ptr); + /// // now with more `as` + /// let ptr_num_cast = ptr as *const i32 as usize; /// - /// There are very few good cases for `transmute`. Most can be achieved - /// through other means. Some commone uses, and the less unsafe way, are as - /// follows: /// - /// ``` /// // Turning a *mut T into an &mut T /// let ptr: *mut i32 = &mut 0; - /// let reF_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr); + /// let ref_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr); + /// // Use reborrows /// let ref_casted = &mut *ptr; - /// ``` /// - /// ``` + /// /// // Turning an &mut T into an &mut U /// let ptr = &mut 0; /// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr); - /// // There is a better way, using `as` and reborrowing: - /// let val_casts = &mut *(ptr as *mut T as *mut U); - /// ``` + /// // Reborrowing continues to play a role here, but now we add `as` casts + /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); + /// + /// + /// // Turning an `&str` into an `&[u8]` + /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // this is not a good way to do this. + /// // use .as_bytes() + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // Or, just use a byte string, if you have control over the string + /// // literal + /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// /// - /// ``` /// // Copying an `&mut T` to reslice: /// fn split_at_mut_transmute(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { @@ -345,7 +354,7 @@ extern "rust-intrinsic" { /// let slice2 = std::mem::transmute::<&mut [T], &mut [T]>(slice); /// (slice[0..index], slice2[index..len]) /// } - /// // or: + /// // Again, use `as` and reborrowing /// fn split_at_mut_casts(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); @@ -355,12 +364,15 @@ extern "rust-intrinsic" { /// } /// ``` /// - /// There are valid uses of transmute. + /// # Examples + /// + /// There are valid uses of transmute, though they are few and far between. /// /// ``` /// // getting the bitpattern of a floating point type /// let x = std::mem::transmute::(0.0/0.0) /// + /// /// // turning a pointer into a function pointer /// // in file.c: `int foo(void) { ... }` /// let handle: *mut libc::c_void = libc::dlopen( @@ -372,6 +384,7 @@ extern "rust-intrinsic" { /// extern fn() -> libc::c_int>(foo); /// println!("{}", foo()); /// + /// /// // extending an invariant lifetime; this is advanced, very unsafe rust /// struct T<'a>(&'a i32); /// let value = 0; @@ -379,8 +392,6 @@ extern "rust-intrinsic" { /// let ptr = &mut t; /// let ptr_extended = std::mem::transmute::<&mut T, &mut T<'static>>(ptr); /// ``` - /// - /// But these are few and far between. #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; From 6928bbba3a51db12aceb90d3c99dbec1383ce2dc Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 2 Jul 2016 00:00:04 -0700 Subject: [PATCH 03/14] Fix some other small nits --- src/libcore/intrinsics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index c7ea5e9da640b..3cc113f5e0a7a 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -316,7 +316,7 @@ extern "rust-intrinsic" { /// // turning a pointer into a usize /// let ptr = &0; /// let ptr_num_transmute = std::mem::transmute::<&i32, usize>(ptr); - /// // now with more `as` + /// // Use `as` casts instead /// let ptr_num_cast = ptr as *const i32 as usize; /// /// @@ -330,15 +330,15 @@ extern "rust-intrinsic" { /// // Turning an &mut T into an &mut U /// let ptr = &mut 0; /// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr); - /// // Reborrowing continues to play a role here, but now we add `as` casts + /// // Now let's put together `as` and reborrowing /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); /// /// /// // Turning an `&str` into an `&[u8]` + /// // this is not a good way to do this. /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; /// assert_eq!(slice, [82, 117, 115, 116]); - /// // this is not a good way to do this. - /// // use .as_bytes() + /// // You could use `str::as_bytes` /// let slice = "Rust".as_bytes(); /// assert_eq!(slice, [82, 117, 115, 116]); /// // Or, just use a byte string, if you have control over the string From 2413b52b886bc9ba4db6c5bc5eb0712c6e4f554a Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 2 Jul 2016 00:07:36 -0700 Subject: [PATCH 04/14] More nits :P --- src/libcore/intrinsics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 3cc113f5e0a7a..d2bf9d94399ea 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -280,7 +280,8 @@ extern "rust-intrinsic" { /// Reinterprets the bits of a value of one type as another type. Both types /// must have the same size. Neither the original, nor the result, may be an - /// invalid value, or else you'll have UB on your hands. + /// [invalid value] + /// (https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html). /// /// `transmute::(t)` is semantically equivalent to the following: /// @@ -300,9 +301,8 @@ extern "rust-intrinsic" { /// cause undefined behavior with this function. `transmute` should be /// the absolute last resort. /// - /// The following is more complete documentation. Read it before using - /// `transmute`: - /// [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) + /// The [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) has + /// more complete documentation. Read it before using `transmute`. /// /// # Alternatives /// From 377bbfe96b9d5f20ca6aec84f68ad8161f307ab5 Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 2 Jul 2016 08:45:01 -0700 Subject: [PATCH 05/14] Add a new alternative --- src/libcore/intrinsics.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index d2bf9d94399ea..5bd35ae1ac25c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -346,6 +346,29 @@ extern "rust-intrinsic" { /// assert_eq!(b"Rust", [82, 117, 116, 116]); /// /// + /// // Turning a Vec<&T> into a Vec> + /// let store = [0, 1, 2, 3]; + /// let v_orig = store.iter().collect::>(); + /// // Using transmute; Undefined Behavior + /// let v_transmuted = mem::transmute::, Vec>>( + /// v_orig); + /// // The suggested, safe way + /// let v_collected = v_orig.into_iter() + /// .map(|r| Some(r)) + /// .collect::>>(); + /// // The no-copy, unsafe way, still using transmute, but not UB + /// let v_no_copy = Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()); + /// mem::forget(v_orig); + /// // This is equivalent to the original, but safer, and reuses the same + /// // Vec internals. Therefore the new inner type must have the exact same + /// // size, and the same or lesser alignment, as the old type. + /// // The same caveats exist for this method as transmute, for the original + /// // inner type (`&i32`) to the converted inner type (`Option<&i32>`), so + /// // read the nomicon page linked above. + /// + /// /// // Copying an `&mut T` to reslice: /// fn split_at_mut_transmute(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { From 9e94ebf268385686299b6838b41e8e04a874259f Mon Sep 17 00:00:00 2001 From: ubsan Date: Sat, 2 Jul 2016 22:55:30 -0700 Subject: [PATCH 06/14] Make sure the documentation compiles --- src/libcore/intrinsics.rs | 169 +++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 77 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 5bd35ae1ac25c..ce87bd3ba326c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -287,12 +287,12 @@ extern "rust-intrinsic" { /// /// ``` /// // assuming that T and U are the same size - /// fn transmute(t: T) -> U { - /// let u: U = std::mem::uninitialized(); + /// unsafe fn transmute(t: T) -> U { + /// let u: U = mem::uninitialized(); /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, /// &mut u as *mut U as *mut u8, - /// std::mem::size_of::()); - /// std::mem::forget(t); + /// mem::size_of::()); + /// mem::forget(t); /// u /// } /// ``` @@ -314,76 +314,85 @@ extern "rust-intrinsic" { /// use std::mem; /// /// // turning a pointer into a usize - /// let ptr = &0; - /// let ptr_num_transmute = std::mem::transmute::<&i32, usize>(ptr); - /// // Use `as` casts instead - /// let ptr_num_cast = ptr as *const i32 as usize; - /// + /// { + /// let ptr = &0; + /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); + /// // Use `as` casts instead + /// let ptr_num_cast = ptr as *const i32 as usize; + /// } /// /// // Turning a *mut T into an &mut T - /// let ptr: *mut i32 = &mut 0; - /// let ref_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr); - /// // Use reborrows - /// let ref_casted = &mut *ptr; - /// + /// { + /// let ptr: *mut i32 = &mut 0; + /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); + /// // Use reborrows + /// let ref_casted = &mut *ptr; + /// } /// /// // Turning an &mut T into an &mut U - /// let ptr = &mut 0; - /// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr); - /// // Now let's put together `as` and reborrowing - /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); - /// + /// { + /// let ptr = &mut 0; + /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); + /// // Now let's put together `as` and reborrowing + /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); + /// } /// /// // Turning an `&str` into an `&[u8]` - /// // this is not a good way to do this. - /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // You could use `str::as_bytes` - /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // Or, just use a byte string, if you have control over the string - /// // literal - /// assert_eq!(b"Rust", [82, 117, 116, 116]); - /// + /// { + /// // this is not a good way to do this. + /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // You could use `str::as_bytes` + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // Or, just use a byte string, if you have control over the string + /// // literal + /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// } /// /// // Turning a Vec<&T> into a Vec> - /// let store = [0, 1, 2, 3]; - /// let v_orig = store.iter().collect::>(); - /// // Using transmute; Undefined Behavior - /// let v_transmuted = mem::transmute::, Vec>>( - /// v_orig); - /// // The suggested, safe way - /// let v_collected = v_orig.into_iter() - /// .map(|r| Some(r)) - /// .collect::>>(); - /// // The no-copy, unsafe way, still using transmute, but not UB - /// let v_no_copy = Vec::from_raw_parts(v_orig.as_mut_ptr(), - /// v_orig.len(), - /// v_orig.capacity()); - /// mem::forget(v_orig); - /// // This is equivalent to the original, but safer, and reuses the same - /// // Vec internals. Therefore the new inner type must have the exact same - /// // size, and the same or lesser alignment, as the old type. - /// // The same caveats exist for this method as transmute, for the original - /// // inner type (`&i32`) to the converted inner type (`Option<&i32>`), so - /// // read the nomicon page linked above. + /// { + /// let store = [0, 1, 2, 3]; + /// let v_orig = store.iter().collect::>(); + /// // Using transmute; Undefined Behavior + /// let v_transmuted = mem::transmute::, Vec>>( + /// v_orig.clone()); + /// // The suggested, safe way + /// let v_collected = v_orig.clone() + /// .into_iter() + /// .map(|r| Some(r)) + /// .collect::>>(); + /// // The no-copy, unsafe way, still using transmute, but not UB + /// // This is equivalent to the original, but safer, and reuses the + /// // same Vec internals. Therefore the new inner type must have the + /// // exact same size, and the same or lesser alignment, as the old + /// // type. The same caveats exist for this method as transmute, for + /// // the original inner type (`&i32`) to the converted inner type + /// // (`Option<&i32>`), so read the nomicon page linked above. + /// let v_no_copy = Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()); + /// mem::forget(v_orig); + /// } /// /// /// // Copying an `&mut T` to reslice: - /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// { + /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); + /// (slice[0..index], slice2[index..len]) + /// } + /// // Again, use `as` and reborrowing + /// fn split_at_mut_casts(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(index < len); - /// let slice2 = std::mem::transmute::<&mut [T], &mut [T]>(slice); - /// (slice[0..index], slice2[index..len]) - /// } - /// // Again, use `as` and reborrowing - /// fn split_at_mut_casts(slice: &mut [T], index: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(index < len); - /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! - /// (slice[0..index], slice2[index..len]) + /// let len = slice.len(); + /// assert!(index < len); + /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! + /// (slice[0..index], slice2[index..len]) + /// } /// } /// ``` /// @@ -393,27 +402,33 @@ extern "rust-intrinsic" { /// /// ``` /// // getting the bitpattern of a floating point type - /// let x = std::mem::transmute::(0.0/0.0) + /// { + /// let x = mem::transmute::(0.0/0.0) + /// } /// /// /// // turning a pointer into a function pointer - /// // in file.c: `int foo(void) { ... }` - /// let handle: *mut libc::c_void = libc::dlopen( - /// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY); - /// let foo: *mut libc::c_void = libc::dlsym( - /// handle, - /// b"foo\0".as_ptr() as *const libc::c_char); - /// let foo = std::mem::transmute::<*mut libc::c_void, - /// extern fn() -> libc::c_int>(foo); - /// println!("{}", foo()); + /// { + /// // in file.c: `int foo(void) { ... }` + /// let handle: *mut libc::c_void = libc::dlopen( + /// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY); + /// let foo: *mut libc::c_void = libc::dlsym( + /// handle, + /// b"foo\0".as_ptr() as *const libc::c_char); + /// let foo = mem::transmute::<*mut libc::c_void, + /// extern fn() -> libc::c_int>(foo); + /// println!("{}", foo()); + /// } /// /// /// // extending an invariant lifetime; this is advanced, very unsafe rust - /// struct T<'a>(&'a i32); - /// let value = 0; - /// let t = T::new(&value); - /// let ptr = &mut t; - /// let ptr_extended = std::mem::transmute::<&mut T, &mut T<'static>>(ptr); + /// { + /// struct T<'a>(&'a i32); + /// let value = 0; + /// let t = T::new(&value); + /// let ptr = &mut t; + /// let ptr_extended = mem::transmute::<&mut T, &mut T<'static>>(ptr); + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; From 7ec44e6c7b0e5fb2ddbc281aa74b515f8ea4e16b Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 10:40:59 -0700 Subject: [PATCH 07/14] Fix tests --- src/libcore/intrinsics.rs | 238 ++++++++++++++++++++++---------------- 1 file changed, 138 insertions(+), 100 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ce87bd3ba326c..fd23598a84715 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -286,12 +286,13 @@ extern "rust-intrinsic" { /// `transmute::(t)` is semantically equivalent to the following: /// /// ``` + /// use std::{mem, ptr}; /// // assuming that T and U are the same size /// unsafe fn transmute(t: T) -> U { - /// let u: U = mem::uninitialized(); - /// std::ptr::copy_nonoverlapping(&t as *const T as *const u8, - /// &mut u as *mut U as *mut u8, - /// mem::size_of::()); + /// let mut u: U = mem::uninitialized(); + /// ptr::copy_nonoverlapping(&t as *const T as *const u8, + /// &mut u as *mut U as *mut u8, + /// mem::size_of::()); /// mem::forget(t); /// u /// } @@ -310,88 +311,115 @@ extern "rust-intrinsic" { /// through other means. Some more or less common uses, and a better way, /// are as follows: /// + /// Turning a pointer into a `usize`: + /// ``` + /// let ptr = &0; + /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); + /// // Use `as` casts instead + /// let ptr_num_cast = ptr as *const i32 as usize; /// ``` - /// use std::mem; - /// - /// // turning a pointer into a usize - /// { - /// let ptr = &0; - /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); - /// // Use `as` casts instead - /// let ptr_num_cast = ptr as *const i32 as usize; - /// } - /// - /// // Turning a *mut T into an &mut T - /// { - /// let ptr: *mut i32 = &mut 0; - /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); - /// // Use reborrows - /// let ref_casted = &mut *ptr; - /// } /// - /// // Turning an &mut T into an &mut U - /// { - /// let ptr = &mut 0; - /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); - /// // Now let's put together `as` and reborrowing - /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); - /// } + /// Turning a `*mut T` into an `&mut T`: + /// ``` + /// let ptr: *mut i32 = &mut 0; + /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); + /// // Use reborrows + /// let ref_casted = &mut *ptr; + /// ``` /// - /// // Turning an `&str` into an `&[u8]` - /// { - /// // this is not a good way to do this. - /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // You could use `str::as_bytes` - /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, [82, 117, 115, 116]); - /// // Or, just use a byte string, if you have control over the string - /// // literal - /// assert_eq!(b"Rust", [82, 117, 116, 116]); - /// } + /// Turning an `&mut T` into an `&mut U`: + /// ``` + /// let ptr = &mut 0; + /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); + /// // Now let's put together `as` and reborrowing + /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); + /// ``` /// - /// // Turning a Vec<&T> into a Vec> - /// { - /// let store = [0, 1, 2, 3]; - /// let v_orig = store.iter().collect::>(); - /// // Using transmute; Undefined Behavior - /// let v_transmuted = mem::transmute::, Vec>>( - /// v_orig.clone()); - /// // The suggested, safe way - /// let v_collected = v_orig.clone() - /// .into_iter() - /// .map(|r| Some(r)) - /// .collect::>>(); - /// // The no-copy, unsafe way, still using transmute, but not UB - /// // This is equivalent to the original, but safer, and reuses the - /// // same Vec internals. Therefore the new inner type must have the - /// // exact same size, and the same or lesser alignment, as the old - /// // type. The same caveats exist for this method as transmute, for - /// // the original inner type (`&i32`) to the converted inner type - /// // (`Option<&i32>`), so read the nomicon page linked above. - /// let v_no_copy = Vec::from_raw_parts(v_orig.as_mut_ptr(), - /// v_orig.len(), - /// v_orig.capacity()); - /// mem::forget(v_orig); - /// } + /// Turning an `&str` into an `&[u8]`: + /// ``` + /// // this is not a good way to do this. + /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // You could use `str::as_bytes` + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, [82, 117, 115, 116]); + /// // Or, just use a byte string, if you have control over the string + /// // literal + /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// ``` /// + /// Turning a `Vec<&T>` into a `Vec>`: + /// ``` + /// let store = [0, 1, 2, 3]; + /// let v_orig = store.iter().collect::>(); + /// // Using transmute: this is Undefined Behavior, and a bad idea + /// // However, it is no-copy + /// let v_transmuted = mem::transmute::, Vec>>( + /// v_orig.clone()); + /// // This is the suggested, safe way + /// // It does copy the entire Vector, though, into a new array + /// let v_collected = v_orig.clone() + /// .into_iter() + /// .map(|r| Some(r)) + /// .collect::>>(); + /// // The no-copy, unsafe way, still using transmute, but not UB + /// // This is equivalent to the original, but safer, and reuses the + /// // same Vec internals. Therefore the new inner type must have the + /// // exact same size, and the same or lesser alignment, as the old + /// // type. The same caveats exist for this method as transmute, for + /// // the original inner type (`&i32`) to the converted inner type + /// // (`Option<&i32>`), so read the nomicon page linked above. + /// let v_from_raw = Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()); + /// mem::forget(v_orig); + /// ``` /// - /// // Copying an `&mut T` to reslice: - /// { - /// fn split_at_mut_transmute(slice: &mut [T], index: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(index < len); + /// Implemententing `split_at_mut`: + /// ``` + /// use std::{slice, mem}; + /// // There are multiple ways to do this; and there are multiple problems + /// // with the following, transmute, way + /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// unsafe { /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); - /// (slice[0..index], slice2[index..len]) + /// // first: transmute is not typesafe; all it checks is that T and + /// // U are of the same size. Second, right here, you have two + /// // mutable references pointing to the same memory + /// (&mut slice[0..index], &mut slice2[index..len]) /// } - /// // Again, use `as` and reborrowing - /// fn split_at_mut_casts(slice: &mut [T], index: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(index < len); - /// let slice2 = &mut *(slice as *mut [T]); // actually typesafe! - /// (slice[0..index], slice2[index..len]) + /// } + /// // This gets rid of the typesafety problems; `&mut *` will *only* give + /// // you an &mut T from an &mut T or *mut T + /// fn split_at_mut_casts(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(index < len); + /// unsafe { + /// let slice2 = &mut *(slice as *mut [T]); + /// // however, you still have two mutable references pointing to + /// // the same memory + /// (&mut slice[0..index], &mut slice2[index..len]) + /// } + /// } + /// // This is how the standard library does it. This is the best method, if + /// // you need to do something like this + /// fn split_at_stdlib(slice: &mut [T], index: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = self.len(); + /// let ptr = self.as_mut_ptr(); + /// unsafe { + /// assert!(mid <= len); + /// // This now has three mutable references pointing at the same + /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. + /// // However, `slice` is never used after `let ptr = ...`, and so + /// // one can treat it as "dead", and therefore, you only have two + /// // real mutable slices. + /// (slice::from_raw_parts_mut(ptr, mid), + /// slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) /// } /// } /// ``` @@ -400,39 +428,49 @@ extern "rust-intrinsic" { /// /// There are valid uses of transmute, though they are few and far between. /// + /// Getting the bitpattern of a floating point type: + /// ``` + /// let bitpattern = std::mem::transmute::(1.0); + /// assert_eq!(bitpattern, 0x3F800000); /// ``` - /// // getting the bitpattern of a floating point type - /// { - /// let x = mem::transmute::(0.0/0.0) + /// + /// Turning a pointer into a function pointer (this isn't guaranteed to + /// work in Rust, although, for example, Linux does make this guarantee): + /// ``` + /// fn foo() -> i32 { + /// 0 /// } + /// let pointer = foo as *const (); + /// let function = std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// assert_eq!(function(), 0); + /// ``` /// + /// Extending a lifetime, or shortening an invariant an invariant lifetime; + /// this is advanced, very unsafe rust: + /// ``` + /// use std::mem; /// - /// // turning a pointer into a function pointer - /// { - /// // in file.c: `int foo(void) { ... }` - /// let handle: *mut libc::c_void = libc::dlopen( - /// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY); - /// let foo: *mut libc::c_void = libc::dlsym( - /// handle, - /// b"foo\0".as_ptr() as *const libc::c_char); - /// let foo = mem::transmute::<*mut libc::c_void, - /// extern fn() -> libc::c_int>(foo); - /// println!("{}", foo()); + /// struct R<'a>(&'a i32); + /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { + /// mem::transmute::, R<'static>>(ptr); /// } /// - /// - /// // extending an invariant lifetime; this is advanced, very unsafe rust - /// { - /// struct T<'a>(&'a i32); - /// let value = 0; - /// let t = T::new(&value); - /// let ptr = &mut t; - /// let ptr_extended = mem::transmute::<&mut T, &mut T<'static>>(ptr); + /// unsafe fn shorten_invariant<'b, 'c>(r: &'b mut R<'static>) + /// -> &'b R<'c> { + /// let ref_to_original = + /// mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>( + /// ref_to_extended); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; + /// Gives the address for the return value of the enclosing function. + /// + /// Using this intrinsic in a function that does not use an out pointer + /// will trigger a compiler error. + pub fn return_address() -> *const u8; + /// Returns `true` if the actual type given as `T` requires drop /// glue; returns `false` if the actual type provided for `T` /// implements `Copy`. From 8c7668a903fb31f8bd767ed5c2a1e1fd3c778915 Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 15:15:33 -0700 Subject: [PATCH 08/14] Fix nits --- src/libcore/intrinsics.rs | 41 ++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index fd23598a84715..1ccdbb3411c8d 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -312,30 +312,34 @@ extern "rust-intrinsic" { /// are as follows: /// /// Turning a pointer into a `usize`: + /// /// ``` /// let ptr = &0; /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); - /// // Use `as` casts instead + /// // Use an `as` cast instead /// let ptr_num_cast = ptr as *const i32 as usize; /// ``` /// /// Turning a `*mut T` into an `&mut T`: + /// /// ``` /// let ptr: *mut i32 = &mut 0; /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); - /// // Use reborrows + /// // Use a reborrow instead /// let ref_casted = &mut *ptr; /// ``` /// /// Turning an `&mut T` into an `&mut U`: + /// /// ``` /// let ptr = &mut 0; /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); - /// // Now let's put together `as` and reborrowing + /// // Now, put together `as` and reborrowing /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); /// ``` /// /// Turning an `&str` into an `&[u8]`: + /// /// ``` /// // this is not a good way to do this. /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; @@ -349,20 +353,21 @@ extern "rust-intrinsic" { /// ``` /// /// Turning a `Vec<&T>` into a `Vec>`: + /// /// ``` /// let store = [0, 1, 2, 3]; /// let v_orig = store.iter().collect::>(); - /// // Using transmute: this is Undefined Behavior, and a bad idea - /// // However, it is no-copy + /// // Using transmute: this is Undefined Behavior, and a bad idea. + /// // However, it is no-copy. /// let v_transmuted = mem::transmute::, Vec>>( /// v_orig.clone()); - /// // This is the suggested, safe way - /// // It does copy the entire Vector, though, into a new array + /// // This is the suggested, safe way. + /// // It does copy the entire Vector, though, into a new array. /// let v_collected = v_orig.clone() /// .into_iter() /// .map(|r| Some(r)) /// .collect::>>(); - /// // The no-copy, unsafe way, still using transmute, but not UB + /// // The no-copy, unsafe way, still using transmute, but not UB. /// // This is equivalent to the original, but safer, and reuses the /// // same Vec internals. Therefore the new inner type must have the /// // exact same size, and the same or lesser alignment, as the old @@ -375,11 +380,12 @@ extern "rust-intrinsic" { /// mem::forget(v_orig); /// ``` /// - /// Implemententing `split_at_mut`: + /// Implementing `split_at_mut`: + /// /// ``` /// use std::{slice, mem}; /// // There are multiple ways to do this; and there are multiple problems - /// // with the following, transmute, way + /// // with the following, transmute, way. /// fn split_at_mut_transmute(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); @@ -388,12 +394,12 @@ extern "rust-intrinsic" { /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); /// // first: transmute is not typesafe; all it checks is that T and /// // U are of the same size. Second, right here, you have two - /// // mutable references pointing to the same memory + /// // mutable references pointing to the same memory. /// (&mut slice[0..index], &mut slice2[index..len]) /// } /// } /// // This gets rid of the typesafety problems; `&mut *` will *only* give - /// // you an &mut T from an &mut T or *mut T + /// // you an `&mut T` from an `&mut T` or `*mut T`. /// fn split_at_mut_casts(slice: &mut [T], index: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); @@ -401,7 +407,7 @@ extern "rust-intrinsic" { /// unsafe { /// let slice2 = &mut *(slice as *mut [T]); /// // however, you still have two mutable references pointing to - /// // the same memory + /// // the same memory. /// (&mut slice[0..index], &mut slice2[index..len]) /// } /// } @@ -415,9 +421,9 @@ extern "rust-intrinsic" { /// assert!(mid <= len); /// // This now has three mutable references pointing at the same /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. - /// // However, `slice` is never used after `let ptr = ...`, and so - /// // one can treat it as "dead", and therefore, you only have two - /// // real mutable slices. + /// // `slice` is never used after `let ptr = ...`, and so one can + /// // treat it as "dead", and therefore, you only have two real + /// // mutable slices. /// (slice::from_raw_parts_mut(ptr, mid), /// slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) /// } @@ -429,6 +435,7 @@ extern "rust-intrinsic" { /// There are valid uses of transmute, though they are few and far between. /// /// Getting the bitpattern of a floating point type: + /// /// ``` /// let bitpattern = std::mem::transmute::(1.0); /// assert_eq!(bitpattern, 0x3F800000); @@ -436,6 +443,7 @@ extern "rust-intrinsic" { /// /// Turning a pointer into a function pointer (this isn't guaranteed to /// work in Rust, although, for example, Linux does make this guarantee): + /// /// ``` /// fn foo() -> i32 { /// 0 @@ -447,6 +455,7 @@ extern "rust-intrinsic" { /// /// Extending a lifetime, or shortening an invariant an invariant lifetime; /// this is advanced, very unsafe rust: + /// /// ``` /// use std::mem; /// From 15a49fefcb29590554d69081a7e26fcf4bfa0f65 Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 15:42:48 -0700 Subject: [PATCH 09/14] Tone it down a little --- src/libcore/intrinsics.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1ccdbb3411c8d..fd2d9cdb0d4b9 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -283,7 +283,7 @@ extern "rust-intrinsic" { /// [invalid value] /// (https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html). /// - /// `transmute::(t)` is semantically equivalent to the following: + /// `transmute` is semantically equivalent to the following: /// /// ``` /// use std::{mem, ptr}; @@ -303,7 +303,7 @@ extern "rust-intrinsic" { /// the absolute last resort. /// /// The [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) has - /// more complete documentation. Read it before using `transmute`. + /// additional documentation. /// /// # Alternatives /// @@ -343,13 +343,13 @@ extern "rust-intrinsic" { /// ``` /// // this is not a good way to do this. /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, [82, 117, 115, 116]); + /// assert_eq!(slice, &[82, 117, 115, 116]); /// // You could use `str::as_bytes` /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, [82, 117, 115, 116]); + /// assert_eq!(slice, &[82, 117, 115, 116]); /// // Or, just use a byte string, if you have control over the string /// // literal - /// assert_eq!(b"Rust", [82, 117, 116, 116]); + /// assert_eq!(b"Rust", &[82, 117, 116, 116]); /// ``` /// /// Turning a `Vec<&T>` into a `Vec>`: @@ -373,7 +373,7 @@ extern "rust-intrinsic" { /// // exact same size, and the same or lesser alignment, as the old /// // type. The same caveats exist for this method as transmute, for /// // the original inner type (`&i32`) to the converted inner type - /// // (`Option<&i32>`), so read the nomicon page linked above. + /// // (`Option<&i32>`), so read the nomicon pages linked above. /// let v_from_raw = Vec::from_raw_parts(v_orig.as_mut_ptr(), /// v_orig.len(), /// v_orig.capacity()); @@ -441,7 +441,7 @@ extern "rust-intrinsic" { /// assert_eq!(bitpattern, 0x3F800000); /// ``` /// - /// Turning a pointer into a function pointer (this isn't guaranteed to + /// Turning a pointer into a function pointer (this is not guaranteed to /// work in Rust, although, for example, Linux does make this guarantee): /// /// ``` @@ -453,8 +453,8 @@ extern "rust-intrinsic" { /// assert_eq!(function(), 0); /// ``` /// - /// Extending a lifetime, or shortening an invariant an invariant lifetime; - /// this is advanced, very unsafe rust: + /// Extending a lifetime, or shortening an invariant lifetime; this is + /// advanced, very unsafe rust: /// /// ``` /// use std::mem; @@ -464,11 +464,10 @@ extern "rust-intrinsic" { /// mem::transmute::, R<'static>>(ptr); /// } /// - /// unsafe fn shorten_invariant<'b, 'c>(r: &'b mut R<'static>) - /// -> &'b R<'c> { - /// let ref_to_original = - /// mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>( - /// ref_to_extended); + /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) + /// -> &'b mut R<'c> { + /// mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>( + /// ref_to_extended) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] From 451af791dadf5a38da2fe63d578c083b95d6c10a Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 16:04:58 -0700 Subject: [PATCH 10/14] Fix links, change example to english --- src/libcore/intrinsics.rs | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index fd2d9cdb0d4b9..875fa08f78980 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -278,32 +278,21 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. pub fn forget(_: T) -> (); - /// Reinterprets the bits of a value of one type as another type. Both types + /// Reinterprets the bits of a value of one type as another type; both types /// must have the same size. Neither the original, nor the result, may be an - /// [invalid value] - /// (https://doc.rust-lang.org/nomicon/meet-safe-and-unsafe.html). + /// [invalid value] (../../nomicon/meet-safe-and-unsafe.html). /// - /// `transmute` is semantically equivalent to the following: - /// - /// ``` - /// use std::{mem, ptr}; - /// // assuming that T and U are the same size - /// unsafe fn transmute(t: T) -> U { - /// let mut u: U = mem::uninitialized(); - /// ptr::copy_nonoverlapping(&t as *const T as *const u8, - /// &mut u as *mut U as *mut u8, - /// mem::size_of::()); - /// mem::forget(t); - /// u - /// } - /// ``` + /// `transmute` is semantically equivalent to a bitwise move of one type + /// into another. It copies the bits from the destination type into the + /// source type, then forgets the original. If you know C or C++, it's like + /// `memcpy` under the hood. /// /// `transmute` is incredibly unsafe. There are a vast number of ways to /// cause undefined behavior with this function. `transmute` should be /// the absolute last resort. /// - /// The [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html) has - /// additional documentation. + /// The [nomicon](../../nomicon/transmutes.html) has additional + /// documentation. /// /// # Alternatives /// From 7eabff5b5ade1cdef3e4b4d3479c45798425ff6a Mon Sep 17 00:00:00 2001 From: ubsan Date: Tue, 5 Jul 2016 23:54:34 -0700 Subject: [PATCH 11/14] Hopefully, it now works --- src/libcore/intrinsics.rs | 73 ++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 875fa08f78980..953173f8aace8 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -304,7 +304,9 @@ extern "rust-intrinsic" { /// /// ``` /// let ptr = &0; - /// let ptr_num_transmute = mem::transmute::<&i32, usize>(ptr); + /// let ptr_num_transmute = unsafe { + /// std::mem::transmute::<&i32, usize>(ptr) + /// }; /// // Use an `as` cast instead /// let ptr_num_cast = ptr as *const i32 as usize; /// ``` @@ -313,43 +315,49 @@ extern "rust-intrinsic" { /// /// ``` /// let ptr: *mut i32 = &mut 0; - /// let ref_transmuted = mem::transmute::<*mut i32, &mut i32>(ptr); + /// let ref_transmuted = unsafe { + /// std::mem::transmute::<*mut i32, &mut i32>(ptr) + /// }; /// // Use a reborrow instead - /// let ref_casted = &mut *ptr; + /// let ref_casted = unsafe { &mut *ptr }; /// ``` /// /// Turning an `&mut T` into an `&mut U`: /// /// ``` /// let ptr = &mut 0; - /// let val_transmuted = mem::transmute::<&mut i32, &mut u32>(ptr); + /// let val_transmuted = unsafe { + /// std::mem::transmute::<&mut i32, &mut u32>(ptr) + /// }; /// // Now, put together `as` and reborrowing - /// let val_casts = &mut *(ptr as *mut i32 as *mut u32); + /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; /// ``` /// /// Turning an `&str` into an `&[u8]`: /// /// ``` /// // this is not a good way to do this. - /// let slice = unsafe { mem::transmute::<&str, &[u8]>("Rust") }; + /// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; /// assert_eq!(slice, &[82, 117, 115, 116]); /// // You could use `str::as_bytes` /// let slice = "Rust".as_bytes(); /// assert_eq!(slice, &[82, 117, 115, 116]); /// // Or, just use a byte string, if you have control over the string /// // literal - /// assert_eq!(b"Rust", &[82, 117, 116, 116]); + /// assert_eq!(b"Rust", &[82, 117, 115, 116]); /// ``` /// /// Turning a `Vec<&T>` into a `Vec>`: /// /// ``` /// let store = [0, 1, 2, 3]; - /// let v_orig = store.iter().collect::>(); + /// let mut v_orig = store.iter().collect::>(); /// // Using transmute: this is Undefined Behavior, and a bad idea. /// // However, it is no-copy. - /// let v_transmuted = mem::transmute::, Vec>>( - /// v_orig.clone()); + /// let v_transmuted = unsafe { + /// std::mem::transmute::, Vec>>( + /// v_orig.clone()) + /// }; /// // This is the suggested, safe way. /// // It does copy the entire Vector, though, into a new array. /// let v_collected = v_orig.clone() @@ -363,10 +371,12 @@ extern "rust-intrinsic" { /// // type. The same caveats exist for this method as transmute, for /// // the original inner type (`&i32`) to the converted inner type /// // (`Option<&i32>`), so read the nomicon pages linked above. - /// let v_from_raw = Vec::from_raw_parts(v_orig.as_mut_ptr(), - /// v_orig.len(), - /// v_orig.capacity()); - /// mem::forget(v_orig); + /// let v_from_raw = unsafe { + /// Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()) + /// }; + /// std::mem::forget(v_orig); /// ``` /// /// Implementing `split_at_mut`: @@ -375,39 +385,39 @@ extern "rust-intrinsic" { /// use std::{slice, mem}; /// // There are multiple ways to do this; and there are multiple problems /// // with the following, transmute, way. - /// fn split_at_mut_transmute(slice: &mut [T], index: usize) + /// fn split_at_mut_transmute(slice: &mut [T], mid: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); - /// assert!(index < len); + /// assert!(mid <= len); /// unsafe { /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); /// // first: transmute is not typesafe; all it checks is that T and /// // U are of the same size. Second, right here, you have two /// // mutable references pointing to the same memory. - /// (&mut slice[0..index], &mut slice2[index..len]) + /// (&mut slice[0..mid], &mut slice2[mid..len]) /// } /// } /// // This gets rid of the typesafety problems; `&mut *` will *only* give /// // you an `&mut T` from an `&mut T` or `*mut T`. - /// fn split_at_mut_casts(slice: &mut [T], index: usize) + /// fn split_at_mut_casts(slice: &mut [T], mid: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); - /// assert!(index < len); + /// assert!(mid <= len); /// unsafe { /// let slice2 = &mut *(slice as *mut [T]); /// // however, you still have two mutable references pointing to /// // the same memory. - /// (&mut slice[0..index], &mut slice2[index..len]) + /// (&mut slice[0..mid], &mut slice2[mid..len]) /// } /// } /// // This is how the standard library does it. This is the best method, if /// // you need to do something like this - /// fn split_at_stdlib(slice: &mut [T], index: usize) + /// fn split_at_stdlib(slice: &mut [T], mid: usize) /// -> (&mut [T], &mut [T]) { - /// let len = self.len(); - /// let ptr = self.as_mut_ptr(); + /// let len = slice.len(); + /// assert!(mid <= len); /// unsafe { - /// assert!(mid <= len); + /// let ptr = slice.as_mut_ptr(); /// // This now has three mutable references pointing at the same /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. /// // `slice` is never used after `let ptr = ...`, and so one can @@ -426,7 +436,9 @@ extern "rust-intrinsic" { /// Getting the bitpattern of a floating point type: /// /// ``` - /// let bitpattern = std::mem::transmute::(1.0); + /// let bitpattern = unsafe { + /// std::mem::transmute::(1.0) + /// }; /// assert_eq!(bitpattern, 0x3F800000); /// ``` /// @@ -438,7 +450,9 @@ extern "rust-intrinsic" { /// 0 /// } /// let pointer = foo as *const (); - /// let function = std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// let function = unsafe { + /// std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// }; /// assert_eq!(function(), 0); /// ``` /// @@ -446,17 +460,14 @@ extern "rust-intrinsic" { /// advanced, very unsafe rust: /// /// ``` - /// use std::mem; - /// /// struct R<'a>(&'a i32); /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { - /// mem::transmute::, R<'static>>(ptr); + /// std::mem::transmute::, R<'static>>(r) /// } /// /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) /// -> &'b mut R<'c> { - /// mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>( - /// ref_to_extended) + /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] From 97003e56991d3e475f2d4bb18a88c768018041e9 Mon Sep 17 00:00:00 2001 From: ubsan Date: Sun, 10 Jul 2016 06:13:34 +0200 Subject: [PATCH 12/14] Switch around Examples and Alternatives --- src/libcore/intrinsics.rs | 93 ++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 953173f8aace8..ab7545d37dc9e 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -294,11 +294,56 @@ extern "rust-intrinsic" { /// The [nomicon](../../nomicon/transmutes.html) has additional /// documentation. /// + /// # Examples + /// + /// There are a few things that `transmute` is really useful for. + /// + /// Getting the bitpattern of a floating point type (or, more generally, + /// type punning, when T and U aren't pointers): + /// + /// ``` + /// let bitpattern = unsafe { + /// std::mem::transmute::(1.0) + /// }; + /// assert_eq!(bitpattern, 0x3F800000); + /// ``` + /// + /// Turning a pointer into a function pointer: + /// + /// ``` + /// fn foo() -> i32 { + /// 0 + /// } + /// let pointer = foo as *const (); + /// let function = unsafe { + /// std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// }; + /// assert_eq!(function(), 0); + /// ``` + /// + /// Extending a lifetime, or shortening an invariant lifetime; this is + /// advanced, very unsafe rust: + /// + /// ``` + /// struct R<'a>(&'a i32); + /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { + /// std::mem::transmute::, R<'static>>(r) + /// } + /// + /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) + /// -> &'b mut R<'c> { + /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) + /// } + /// ``` + /// /// # Alternatives /// - /// There are very few good cases for `transmute`. Most can be achieved - /// through other means. Some more or less common uses, and a better way, - /// are as follows: + /// However, many uses of `transmute` can be achieved through other means. + /// This is unfortunate because either `transmute` isn't guaranteed to work + /// in that case, and only does because of rustc's current implemenation; + /// or, more commonly, `transmute` is just too powerful. It can transform + /// any type into any other, with just the caveat that they're the same + /// size. Some more or less common uses, and a better way, are as follows: /// /// Turning a pointer into a `usize`: /// @@ -428,48 +473,6 @@ extern "rust-intrinsic" { /// } /// } /// ``` - /// - /// # Examples - /// - /// There are valid uses of transmute, though they are few and far between. - /// - /// Getting the bitpattern of a floating point type: - /// - /// ``` - /// let bitpattern = unsafe { - /// std::mem::transmute::(1.0) - /// }; - /// assert_eq!(bitpattern, 0x3F800000); - /// ``` - /// - /// Turning a pointer into a function pointer (this is not guaranteed to - /// work in Rust, although, for example, Linux does make this guarantee): - /// - /// ``` - /// fn foo() -> i32 { - /// 0 - /// } - /// let pointer = foo as *const (); - /// let function = unsafe { - /// std::mem::transmute::<*const (), fn() -> i32>(pointer) - /// }; - /// assert_eq!(function(), 0); - /// ``` - /// - /// Extending a lifetime, or shortening an invariant lifetime; this is - /// advanced, very unsafe rust: - /// - /// ``` - /// struct R<'a>(&'a i32); - /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { - /// std::mem::transmute::, R<'static>>(r) - /// } - /// - /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) - /// -> &'b mut R<'c> { - /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) - /// } - /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; From c0bee60adbf979ae624cfcdc7610044c357794a0 Mon Sep 17 00:00:00 2001 From: ubsan Date: Sun, 10 Jul 2016 23:17:02 +0200 Subject: [PATCH 13/14] Make it nicer from @alexandermerritt --- src/libcore/intrinsics.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ab7545d37dc9e..d6fb1816b5fa0 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -339,11 +339,11 @@ extern "rust-intrinsic" { /// # Alternatives /// /// However, many uses of `transmute` can be achieved through other means. - /// This is unfortunate because either `transmute` isn't guaranteed to work - /// in that case, and only does because of rustc's current implemenation; - /// or, more commonly, `transmute` is just too powerful. It can transform + /// `transmute` can transform /// any type into any other, with just the caveat that they're the same - /// size. Some more or less common uses, and a better way, are as follows: + /// size, and it sometimes results in interesting results. Below are common + /// applications of `transmute` which can be replaced with safe applications + /// of `as`: /// /// Turning a pointer into a `usize`: /// @@ -374,7 +374,8 @@ extern "rust-intrinsic" { /// let val_transmuted = unsafe { /// std::mem::transmute::<&mut i32, &mut u32>(ptr) /// }; - /// // Now, put together `as` and reborrowing + /// // Now, put together `as` and reborrowing - note the chaining of `as` + /// // `as` is not transitive /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; /// ``` /// From 24f8589bf3d4a198721a5ebe84679817cd1e205b Mon Sep 17 00:00:00 2001 From: ubsan Date: Thu, 21 Jul 2016 12:57:42 -0700 Subject: [PATCH 14/14] Fix nits --- src/libcore/intrinsics.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index d6fb1816b5fa0..6a1d94a2e44d8 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -284,8 +284,8 @@ extern "rust-intrinsic" { /// /// `transmute` is semantically equivalent to a bitwise move of one type /// into another. It copies the bits from the destination type into the - /// source type, then forgets the original. If you know C or C++, it's like - /// `memcpy` under the hood. + /// source type, then forgets the original. It's equivalent to C's `memcpy` + /// under the hood, just like `transmute_copy`. /// /// `transmute` is incredibly unsafe. There are a vast number of ways to /// cause undefined behavior with this function. `transmute` should be @@ -299,7 +299,7 @@ extern "rust-intrinsic" { /// There are a few things that `transmute` is really useful for. /// /// Getting the bitpattern of a floating point type (or, more generally, - /// type punning, when T and U aren't pointers): + /// type punning, when `T` and `U` aren't pointers): /// /// ``` /// let bitpattern = unsafe { @@ -339,11 +339,10 @@ extern "rust-intrinsic" { /// # Alternatives /// /// However, many uses of `transmute` can be achieved through other means. - /// `transmute` can transform - /// any type into any other, with just the caveat that they're the same - /// size, and it sometimes results in interesting results. Below are common - /// applications of `transmute` which can be replaced with safe applications - /// of `as`: + /// `transmute` can transform any type into any other, with just the caveat + /// that they're the same size, and often interesting results occur. Below + /// are common applications of `transmute` which can be replaced with safe + /// applications of `as`: /// /// Turning a pointer into a `usize`: ///