Skip to content

Commit 3d03f75

Browse files
committed
Add more docs - mostly warnings - to std::mem::transmute
1 parent 32a6373 commit 3d03f75

File tree

1 file changed

+95
-4
lines changed

1 file changed

+95
-4
lines changed

src/libcore/intrinsics.rs

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -278,18 +278,109 @@ extern "rust-intrinsic" {
278278
/// Moves a value out of scope without running drop glue.
279279
pub fn forget<T>(_: T) -> ();
280280

281-
/// Unsafely transforms a value of one type into a value of another type.
281+
/// Bitcasts a value of one type to another. Both types must have the same
282+
/// size.
282283
///
283-
/// Both types must have the same size.
284+
/// `transmute::<T, U>(t)` is semantically equivalent to the following:
285+
///
286+
/// ```
287+
/// fn transmute<T, U>(t: T) -> U {
288+
/// let u: U = std::mem::uninitialized();
289+
/// std::ptr::copy_nonoverlapping(&t as *const T as *const u8,
290+
/// &mut u as *mut U as *mut u8,
291+
/// std::mem::size_of::<T>());
292+
/// std::mem::forget(t);
293+
/// u
294+
/// }
295+
/// ```
296+
///
297+
/// `transmute` is incredibly unsafe. There are an incredible number of ways
298+
/// to cause undefined behavior with this function. `transmute` should be
299+
/// the absolute last resort.
300+
///
301+
/// The following is more complete documentation. Read it before using
302+
/// `transmute`:
303+
/// [nomicon](https://doc.rust-lang.org/nomicon/transmutes.html)
284304
///
285305
/// # Examples
286306
///
287307
/// ```
288308
/// use std::mem;
289309
///
290-
/// let array: &[u8] = unsafe { mem::transmute("Rust") };
291-
/// assert_eq!(array, [82, 117, 115, 116]);
310+
/// let slice: &[u8] = unsafe { mem::transmute::<&str, &[u8]>("Rust") };
311+
/// assert_eq!(slice, [82, 117, 115, 116]);
312+
/// // this is not a good way to do this.
313+
/// // use .as_bytes()
314+
/// let slice = "Rust".as_bytes();
315+
/// assert_eq!(slice, [82, 117, 115, 116]);
316+
/// // Or, just use a byte string
317+
/// assert_eq!(b"Rust", [82, 117, 116, 116]);
318+
/// ```
319+
///
320+
/// There are very few good cases for `transmute`. Most can be achieved
321+
/// through other means. Some commone uses, and the less unsafe way, are as
322+
/// follows:
323+
///
324+
/// ```
325+
/// // Turning a *mut T into an &mut T
326+
/// let ptr: *mut i32 = &mut 0;
327+
/// let reF_transmuted = std::mem::transmute::<*mut i32, &mut i32>(ptr);
328+
/// let ref_casted = &mut *ptr;
329+
/// ```
330+
///
292331
/// ```
332+
/// // Turning an &mut T into an &mut U
333+
/// let ptr = &mut 0;
334+
/// let val_transmuted = std::mem::transmute::<&mut i32, &mut u32>(ptr);
335+
/// // There is a better way, using `as` and reborrowing:
336+
/// let val_casts = &mut *(ptr as *mut T as *mut U);
337+
/// ```
338+
///
339+
/// ```
340+
/// // Copying an `&mut T` to reslice:
341+
/// fn split_at_mut_transmute<T>(slice: &mut [T], index: usize)
342+
/// -> (&mut [T], &mut [T]) {
343+
/// let len = slice.len();
344+
/// assert!(index < len);
345+
/// let slice2 = std::mem::transmute::<&mut [T], &mut [T]>(slice);
346+
/// (slice[0..index], slice2[index..len])
347+
/// }
348+
/// // or:
349+
/// fn split_at_mut_casts<T>(slice: &mut [T], index: usize)
350+
/// -> (&mut [T], &mut [T]) {
351+
/// let len = slice.len();
352+
/// assert!(index < len);
353+
/// let slice2 = &mut *(slice as *mut [T]); // actually typesafe!
354+
/// (slice[0..index], slice2[index..len])
355+
/// }
356+
/// ```
357+
///
358+
/// There are valid uses of transmute.
359+
///
360+
/// ```
361+
/// // getting the bitpattern of a floating point type
362+
/// let x = std::mem::transmute::<f32, u32>(0.0/0.0)
363+
///
364+
/// // turning a pointer into a function pointer
365+
/// // in file.c: `int foo(void) { ... }`
366+
/// let handle: *mut libc::c_void = libc::dlopen(
367+
/// b"file.so\0".as_ptr() as *const libc::c_char, libc::RTLD_LAZY);
368+
/// let foo: *mut libc::c_void = libc::dlsym(
369+
/// handle,
370+
/// b"foo\0".as_ptr() as *const libc::c_char);
371+
/// let foo = std::mem::transmute::<*mut libc::c_void,
372+
/// extern fn() -> libc::c_int>(foo);
373+
/// println!("{}", foo());
374+
///
375+
/// // extending an invariant lifetime; this is advanced, very unsafe rust
376+
/// struct T<'a>(&'a i32);
377+
/// let value = 0;
378+
/// let t = T::new(&value);
379+
/// let ptr = &mut t;
380+
/// let ptr_extended = std::mem::transmute::<&mut T, &mut T<'static>>(ptr);
381+
/// ```
382+
///
383+
/// But these are few and far between.
293384
#[stable(feature = "rust1", since = "1.0.0")]
294385
pub fn transmute<T, U>(e: T) -> U;
295386

0 commit comments

Comments
 (0)