# Casting constness can be risky, here's a simple fix

**URL:** <https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933>\
**Category:** Unsafe Code Guidelines\
**Created:** [January 7, 2022, 4:00pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933 "2022-01-07T16:00:54Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![Kixunil](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kixunil/32/4110_2.png) [@Kixunil](https://internals.rust-lang.org/u/Kixunil)\
**Post date:** [January 7, 2022, 4:00pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/1 "2022-01-07T16:00:54Z")

</div>

I just realized it may be risky to cast consts. Consider this code:

```rust
// AtomicPtr is a good real life example of the need to cast pointers
static FOO: AtomicPtr<BigBar> = AtomicPtr::new(ptr::null_mut());

// assume this code is far away from FOO declaration above
fn do_stuff() {
   // load returns *mut _
   let const_ptr = FOO.load(Ordering::Relaxed) as *const BigBar;
   unsafe { do_something_with_const_big_bar(const_ptr); }
}

```

Now imagine someone refactoring FOO by e.g. changing `BigBar` into `SmallBar` (`SmallBar` having smaller size in memory than `BigBar`) and forgetting to change the cast in `do_stuff` and subsequent call. There would be no compile errorbut a silent conversion. `do_something_with_const_big_bar` would be called and possibly read out-of-bounds memory - UB (there are other ways to UB, this is just one example).

The solution is simple - define this function:

```rust
fn ptr_mut_to_const<T>(ptr: *mut T) -> *const T {
    ptr as _
}

```

And use it instead of raw cast.

Great, now you know how to avoid the risk but maybe it'd make sense to go further? We could add this function and it's converse (`const_to_mut`) to `core::ptr` and have a (clippy) lint to suggest it instead of `as`. This would save those people who didn't read this post.

What do you think? Is it worth adding to `core`? Is there a better way? I'm willing to make a PR if experienced Rust devs agree this is a good idea.

---

<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:** [January 7, 2022, 4:46pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/2 "2022-01-07T16:46:33Z")

</div>

Apparently for `*mut T` to `*const T`, there's already an implicit coercion in place, so you don't need to use the `as` at all, and then you're safe for if the type changes.

[Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=477f35c8e07827e715147fae41b548b6)

or

[Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8b823e4eb08e65e7698fe06f4b6ba19f)

For the converse, `*const T` to `*mut T`, a conversion method is quite useful in my opinion, probably as a method of `*mut T`. A (clippy) lint seems like a reasonable idea, too. For consistency, a `*mut T` to `*const T` method can make sense, too. After all, e.g. `&String` to `&str` converts implicitly, too, yet there's also a method for it.

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [January 7, 2022, 4:47pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/3 "2022-01-07T16:47:55Z")

</div>

I fully agree with basically everything you wrote. 🙂 `as` on raw pointers gives me the jeebies, we should avoid it wherever we can.

We already have `cast` which lets one cast the type while preserving mutability, this would basically be dual.

---

<div class="post-metadata">

**Author:** ![Kixunil](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kixunil/32/4110_2.png) [@Kixunil](https://internals.rust-lang.org/u/Kixunil)\
**Post date:** [January 7, 2022, 5:35pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/4 "2022-01-07T17:35:46Z")

</div>

@steffahn 😮 that's interesting! Agree with having both methods.

@RalfJung thanks a lot for feedback! Hearing it from you is very reassuring. I guess it's safe to make a PR now. 🙂

---

<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:** [January 7, 2022, 5:40pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/5 "2022-01-07T17:40:23Z")

</div>

> [@RalfJung](#):
>
> We already have `cast` which lets one cast the type while preserving mutability, this would basically be dual.

It's worth noting that `cast` only works for `Sized` target types, so for `?Sized` types it's still required to use `as`. Pointer metadata might allow us to loosen `cast` to actually say "has the same metadata," depending on the final shape of the feature.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [January 7, 2022, 6:33pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/6 "2022-01-07T18:33:44Z")

</div>

Though you would commonly want to adjust the metadata value, e.g. `*const [u16] -> *const [u8]` needs to double the length.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [January 7, 2022, 8:40pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/7 "2022-01-07T20:40:33Z")

</div>

> [@RalfJung](#):
>
> We already have `cast` which lets one cast the type while preserving mutability, this would basically be dual.

And we also recently got (on nightly) `to_bits` and `from_bits` ([https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.to\_bits](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.to_bits)) as a way to avoid a different kind of `as` cast.

So I also think it makes sense to add methods for the `*mut`\<-\>`*const` casts.

Do people have any thoughts on the names? `as_const` and `as_mut` are the first that jump to mind to me, but it might be interesting to find a longer name for the const-to-mut version than for the other way around, to help make it stand out.

---

<div class="post-metadata">

**Author:** ![mjbshaw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mjbshaw/32/5103_2.png) [@mjbshaw](https://internals.rust-lang.org/u/mjbshaw)\
**Post date:** [January 7, 2022, 8:48pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/8 "2022-01-07T20:48:09Z")

</div>

Aw man, `to_bits` and `from_bits` aren't const? That's unfortunate. And several other pointer methods are const-unstable, despite [their tracking issue](https://github.com/rust-lang/rust/issues/41079) being closed.

Anyway, my request here: please make `as_const`/`as_mut` const.

As for names, I think `as_mut` is great. I'd prefer we don't try to inflate the name just to make it stand out more.

---

<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:** [January 7, 2022, 9:04pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/9 "2022-01-07T21:04:40Z")

</div>

> [@scottmcm](#):
>
> `as_const` and `as_mut` are the first that jump to mind to me, but it might be interesting to find a longer name for the const-to-mut version than for the other way around, to help make it stand out.

`as_mut` already exists. I think `as_mut_ptr` makes sense, which is a method we'd need to steal from `*mut [T]`/[`#![feature(slice_ptr_get)]`](https://github.com/rust-lang/rust/issues/74265) (where IMO the name is inappropriate/confusing anyways, `*mut [T]` already _is_ a mutable ptr; it comes from the `slice::as_mut_ptr` name). As for the inverse, for consistency then `as_const_ptr`. Or `as_const` or `as_ptr` could also work.

_Edit:_ Actually, `as_mut` only exists for `*mut T`, but still IMO, the confusion potential when re-using it is somewhat high.

~~_Edit2:_ For comparison, `NonNull` uses `as_ptr` and `as_mut_ptr` naming for conversion to `*const T` and `*mut T`.~~ No, that's wrong, it uses `as_ptr` to return `*mut T`.

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [January 7, 2022, 9:35pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/10 "2022-01-07T21:35:51Z")

</div>

> [@mjbshaw](#):
>
> Aw man, `to_bits` and `from_bits` aren't const? That's unfortunate.

They aren't and they won't, at least for `to_bits`. Casting between pointers and integers is unsupportable at const-time since we cannot know at which address the object will be placed when the program is being run.

All the others can and should be `const fn` though, true.

---

<div class="post-metadata">

**Author:** ![mjbshaw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mjbshaw/32/5103_2.png) [@mjbshaw](https://internals.rust-lang.org/u/mjbshaw)\
**Post date:** [January 7, 2022, 10:18pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/11 "2022-01-07T22:18:43Z")

</div>

I don't want to sidetrack this too much, but my use case is actually about statics. Non-const fns can't be called when initializing a static, which makes statics kinda annoying to work with (particularly in FFI contexts) ([example](https://rust.godbolt.org/z/8x1f8f1M8); I know I can just use `&'static _` but sometimes an API requires a `usize` and it'd be nice to use the right type from the beginning instead of having to cast it repeatedly; I also know this is orthogonal to this thread since you couldn't even really pass the static address to a const fn for further evaluation/casting, since that value is only known at link time and not compile time; sorry for the tangent and massive parenthetical, I just wish I could make a static `usize` from a static variable's address).

Anyway, I'm happy to hear it's not contentious for these proposed methods to be const.

---

<div class="post-metadata">

**Author:** ![Kixunil](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kixunil/32/4110_2.png) [@Kixunil](https://internals.rust-lang.org/u/Kixunil)\
**Post date:** [January 7, 2022, 10:40pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/12 "2022-01-07T22:40:51Z")

</div>

As I was going to write the PR, I noticed that `cast` only disallows destination to be unsized but allows source to be unsized. [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=891f15962358518be05a67b0e4770c6c)

Is this intended? It doesn't seem to do anything bad but doesn't look right either.

---

<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:** [January 7, 2022, 10:52pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/13 "2022-01-07T22:52:12Z")

</div>

> [@Kixunil](#):
>
> Is this intended? It doesn't seem to do anything bad but doesn't look right either.

I would guess it is indeed intended. Casting pointers with `as` always supports converting from any `?Sized` type to any `Sized` type, but not to arbitrary `?Sized` target types. Unsized to unsized pointer casts (with `as`) only work if the type of the metadata matches, which is the case if both types are containing1 slices (string slice, or any `[T]` size), or if both types are containing1 trait objects for the same trait (with potentially different `+ Send` / `+ Sync` / etc additions).

1By "containing" I mean, that the type `Mutex<dyn Trait>` in a pointer like `*const Mutex<dyn Trait>` _contains_ a `dyn Trait`, and its pointer has consequently the same type of metadata. Or a `struct Foo { x: [u8] }` will make `*const Foo` have the same metadata as `*const [u8]`, or `*mut str`, or other slices..

This relation is impossible to express at type level (at least with stable standard library API), so `cast` methods cannot support them.

---

<div class="post-metadata">

**Author:** ![Kixunil](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kixunil/32/4110_2.png) [@Kixunil](https://internals.rust-lang.org/u/Kixunil)\
**Post date:** [January 7, 2022, 10:56pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/14 "2022-01-07T22:56:33Z")

</div>

Yeah, that occurred to me, what I'm unsure of is whether

- casting unsized pointer to sized is well-defined (guaranteed to drop metadata etc)
- `cast` was written with the intention to support this conversion

---

<div class="post-metadata">

**Author:** ![Kixunil](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kixunil/32/4110_2.png) [@Kixunil](https://internals.rust-lang.org/u/Kixunil)\
**Post date:** [January 7, 2022, 11:07pm UTC](https://internals.rust-lang.org/t/casting-constness-can-be-risky-heres-a-simple-fix/15933/15 "2022-01-07T23:07:42Z")

</div>

Submitted the PR: [Implemented const casts of raw pointers by Kixunil · Pull Request #92657 · rust-lang/rust · GitHub](https://github.com/rust-lang/rust/pull/92657)

---

<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/casting-constness-can-be-risky-heres-a-simple-fix/15933/16 "2024-12-22T17:04:09Z")

</div>

Closed on December 22, 2024, 5:04pm UTC

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