Skip to content

Commit 1e8b29a

Browse files
authored
Rollup merge of rust-lang#97321 - RalfJung:int-to-fnptr, r=Dylan-DPC
explain how to turn integers into fn ptrs (with an intermediate raw ptr, not a direct transmute) Direct int2ptr transmute, under the semantics I am imagining, will produce a ptr with "invalid" provenance that is invalid to deref or call. We cannot give it the same semantics as int2ptr casts since those do [something complicated](https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html). To my great surprise, that is already what the example in the `transmute` docs does. :) I still added a comment to say that that part is important, and I added a section explicitly talking about this to the `fn()` type docs. With rust-lang/miri#2151, Miri will start complaining about direct int-to-fnptr transmutes (in the sense that it is UB to call the resulting pointer).
2 parents 41d203e + eeb0633 commit 1e8b29a

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

core/src/intrinsics.rs

+3
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,9 @@ extern "rust-intrinsic" {
930930
/// fn foo() -> i32 {
931931
/// 0
932932
/// }
933+
/// // Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer.
934+
/// // This avoids an integer-to-pointer `transmute`, which can be problematic.
935+
/// // Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine.
933936
/// let pointer = foo as *const ();
934937
/// let function = unsafe {
935938
/// std::mem::transmute::<*const (), fn() -> i32>(pointer)

core/src/primitive_docs.rs

+26
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,32 @@ mod prim_ref {}
13511351
/// is a reference to the function-specific ZST. `&bar` is basically never what you
13521352
/// want when `bar` is a function.
13531353
///
1354+
/// ### Casting to and from integers
1355+
///
1356+
/// You cast function pointers directly to integers:
1357+
///
1358+
/// ```rust
1359+
/// let fnptr: fn(i32) -> i32 = |x| x+2;
1360+
/// let fnptr_addr = fnptr as usize;
1361+
/// ```
1362+
///
1363+
/// However, a direct cast back is not possible. You need to use `transmute`:
1364+
///
1365+
/// ```rust
1366+
/// # let fnptr: fn(i32) -> i32 = |x| x+2;
1367+
/// # let fnptr_addr = fnptr as usize;
1368+
/// let fnptr = fnptr_addr as *const ();
1369+
/// let fnptr: fn(i32) -> i32 = unsafe { std::mem::transmute(fnptr) };
1370+
/// assert_eq!(fnptr(40), 42);
1371+
/// ```
1372+
///
1373+
/// Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer.
1374+
/// This avoids an integer-to-pointer `transmute`, which can be problematic.
1375+
/// Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine.
1376+
///
1377+
/// Note that all of this is not portable to platforms where function pointers and data pointers
1378+
/// have different sizes.
1379+
///
13541380
/// ### Traits
13551381
///
13561382
/// Function pointers implement the following traits:

std/src/primitive_docs.rs

+26
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,32 @@ mod prim_ref {}
13511351
/// is a reference to the function-specific ZST. `&bar` is basically never what you
13521352
/// want when `bar` is a function.
13531353
///
1354+
/// ### Casting to and from integers
1355+
///
1356+
/// You cast function pointers directly to integers:
1357+
///
1358+
/// ```rust
1359+
/// let fnptr: fn(i32) -> i32 = |x| x+2;
1360+
/// let fnptr_addr = fnptr as usize;
1361+
/// ```
1362+
///
1363+
/// However, a direct cast back is not possible. You need to use `transmute`:
1364+
///
1365+
/// ```rust
1366+
/// # let fnptr: fn(i32) -> i32 = |x| x+2;
1367+
/// # let fnptr_addr = fnptr as usize;
1368+
/// let fnptr = fnptr_addr as *const ();
1369+
/// let fnptr: fn(i32) -> i32 = unsafe { std::mem::transmute(fnptr) };
1370+
/// assert_eq!(fnptr(40), 42);
1371+
/// ```
1372+
///
1373+
/// Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer.
1374+
/// This avoids an integer-to-pointer `transmute`, which can be problematic.
1375+
/// Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine.
1376+
///
1377+
/// Note that all of this is not portable to platforms where function pointers and data pointers
1378+
/// have different sizes.
1379+
///
13541380
/// ### Traits
13551381
///
13561382
/// Function pointers implement the following traits:

0 commit comments

Comments
 (0)