# Transmuting fat pointers

**URL:** https://internals.rust-lang.org/t/transmuting-fat-pointers/17157
**Category:** Unsafe Code Guidelines
**Created:** [August 9, 2022, 2:17pm UTC](https://internals.rust-lang.org/t/transmuting-fat-pointers/17157 "2022-08-09T14:17:41Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![Zakarum](https://avatars.discourse-cdn.com/v4/letter/z/8baadc/32.png) [@Zakarum](https://internals.rust-lang.org/u/Zakarum)
#### Post date: [August 9, 2022, 2:17pm UTC](https://internals.rust-lang.org/t/transmuting-fat-pointers/17157/1 "2022-08-09T14:17:42Z")

</div>

When one needs to "forget" a type of the pointer it's can be safely cast to some other pointer. Usually `*const ()` or `*const u8` is used. Or `NonNull` if null pointer are out of question and niche is nice to have. Later pointer can be cast back to original type and then safely dereferenced.

Typical use case for this is to perform downcasts at runtime when `TypeId` is available externally so no `dyn Any` is required.

This still works for pointers to slices and DST structs with slice field. Except that now the pointer have to be cast to arbitrary slice pointer like `*const [()]`.

And now this doesn't work for `dyn Trait` and generic `T: ?Sized`. Cast between `*const dyn Trait` and `*const dyn OtherTrait` is not allowed. Same as cast between `*const dyn Trait` and `*const [Type]`.

The reason behind this is (as I understand it) that the layout of metadata can be different. So I guess that transmuting those pointers may be UB.

Now I have a problem. I try to make a function signature for function that takes thin pointer to value and TypeId and returns pointer to type with that TypeId or None. The TypeId can be of inner type or of dyn trait. What are my options?

---

<div class="post-metadata">

### Author: ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)
#### Post date: [August 9, 2022, 7:57pm UTC](https://internals.rust-lang.org/t/transmuting-fat-pointers/17157/2 "2022-08-09T19:57:53Z")

</div>

This is a question about using Rust, not about evolving the language, so is a better fit for [the users forum](https://users.rust-lang.org).

To go from `(*mut (), TypeId)` to `*mut impl ?Sized`, the best option is to actually just hold onto `*mut dyn Any`; it's the same size (and perhaps smaller, once `TypeId` is strengthened against collisions), and will automatically avoid soundness issues.

If splitting into two parts is necessary (e.g. to cross FFI), you want to look at the `ptr_metadata` APIs to split `*mut dyn Any` into `(*mut (), DynMetadata<dyn Any>)`.

I do not believe you can soundly directly downcast from `dyn Any` to `dyn Trait`, no matter the language features. You need to know the concrete type in order to select the correct `dyn Trait` vtable, and the `dyn Any` vtable does not and cannot contain this information.

---

<div class="post-metadata">

### Author: ![Zakarum](https://avatars.discourse-cdn.com/v4/letter/z/8baadc/32.png) [@Zakarum](https://internals.rust-lang.org/u/Zakarum)
#### Post date: [August 9, 2022, 9:28pm UTC](https://internals.rust-lang.org/t/transmuting-fat-pointers/17157/3 "2022-08-09T21:28:31Z")

</div>

In my use case I don't carry `TypeId`. At some point I have a `NonNull<T>` that points to an array of `T` and turn it to type-erased `NonNull<u8>` to store in heterogeneous data structure.

At later point I again have `T`, look for a correct `NonNull<u8>` and cast it. Then I can iterate over `&T`.

Now I want to add a layer of abstraction.

During setup a few functions with signature `fn(&T) -> &U where U: ?Sized` can be registered. And wrapped to `fn(NonNull<u8>) -> ???` to store them heterogeneously.  
Now receiver would only know about `U: ?Sized`, has pairs of `NonNull<u8>` and `fn(NonNull<u8>) -> ???` and knowledge that that pointer can be used with that function and that function output was `NonNull<U>` cast into `???`. The problem is, what `???` type should be? I tried transmuting `NonNull<U>` into `NonNull<[u8]>` and back and it worked, but I guess it's UB if `U` is dyn trait. Also works with any dummy dyn trait object type. And probably UB again if `U` is slice.

Currently I rewrote the thing to cast function pointer instead of its output. i.e. I transmute `fn(NonNull<u8>) -> NonNull<U>` to `fn(NonNull<u8>)` to store it and then back to `fn(NonNull<u8>) -> NonNull<U>` to call it.

I wonder if any of the methods I tried could theoretically be not only safe and sound, but defined such.

---

<div class="post-metadata">

### Author: ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)
#### Post date: [August 9, 2022, 10:42pm UTC](https://internals.rust-lang.org/t/transmuting-fat-pointers/17157/4 "2022-08-09T22:42:12Z")

</div>

> [@Zakarum](#):
>
> t some point I have a `NonNull<T>` that points to an array of `T`

This is an important detail. In this case you necessarily have `T: Sized` (to construct a `[T]`), and can cast between `*mut ()` and `*mut T` freely.

> [@Zakarum](#):
>
> I tried transmuting [`for<U: ?Sized>`] `NonNull<U>` into `NonNull<[u8]>` and back and it worked,

[It doesn't](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2247033f7b4c0affa87412df1f3af9b2). I don't know what you transmuted; probably `fn(…) -> …`, which does work. Transmuting between function pointer types is AIUI guaranteed to be sound.

What you probably want is an opaque function pointer type, though. std doesn't have one, but it's [possible to polyfill, kinda](https://docs.rs/sptr/latest/sptr/func/struct.OpaqueFnPtr.html).

---

<div class="post-metadata">

### Author: ![Zakarum](https://avatars.discourse-cdn.com/v4/letter/z/8baadc/32.png) [@Zakarum](https://internals.rust-lang.org/u/Zakarum)
#### Post date: [August 11, 2022, 8:43am UTC](https://internals.rust-lang.org/t/transmuting-fat-pointers/17157/5 "2022-08-11T08:43:56Z")

</div>

Well, it ["works" like this](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=cc2e5dd352ce338c4a7ca683437632bc). But I figured it is either UB or may become UB in future.

I switched to function pointer cast instead. Should be future-proof.

---

<div class="post-metadata">

### Author: ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)
#### Post date: [December 22, 2024, 5:04pm UTC](https://internals.rust-lang.org/t/transmuting-fat-pointers/17157/6 "2024-12-22T17:04:10Z")

</div>

This topic was automatically closed 540 days after the last reply. New replies are no longer allowed.
