# Autotrait to mark types without interior mutability

**URL:** <https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636>\
**Category:** language design\
**Created:** [May 15, 2022, 9:52pm UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636 "2022-05-15T21:52:31Z")\
**Posts on this page:** 14\
**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:** [May 15, 2022, 9:52pm UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/1 "2022-05-15T21:52:31Z")

</div>

So I've being thinking about making cheap copies for types that are not `Copy`.

It appears to me that if I create a bitwise copy of a value, ensure that no copy (including original value) is mutated and only one of the copies is dropped, it should be totally ok, valid and safe. No matter what the type is and what constraints there are. Because semantically accessing copies would be no different to moving original value around. Correct me if I wrong.

And this is possible with some unsafe code.

If I want to make a library that uses the trick and with nice and safe API then a wrapper of some kind would have to take the value by mutable reference or assume ownership and then give only shared references to identical copies. But in the presence of interior mutability it becomes unsound. If some bits of one copy get changed, it won't be reflected in others, making it possible to break some internal constraints. Thus I could add a type bound that restricts safe API only to types that do not have interior mutability, i.e. no `UnsafeCell` among the fields. Such trait marker could be implemented similarly to other unsafe markers like `Send` and `Sync`, be auto-implemented for all types without fields that do not implement it and explicitly not implemented for `UnsafeCell`.

The only other problem I've imaged is that two pointers with different addresses to a value that represents some resource may be considered to point to different resources by some unsafe code.

---

<div class="post-metadata">

**Author:** ![elidupree](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/elidupree/32/4304_2.png) [@elidupree](https://internals.rust-lang.org/u/elidupree)\
**Post date:** [May 15, 2022, 10:41pm UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/2 "2022-05-15T22:41:39Z")

</div>

> [@Zakarum](#):
>
> Because semantically accessing copies would be no different to moving original value around. Correct me if I wrong.

Neat rationale – "if I access the copies in some sequence, it's indistinguishable from if I moved to the original value around in the same order as the accesses, right? We can view the other copies of the value as being merely bitwise identical but not 'real' in some sense."

But I'm pretty sure it overlooks at least one case. Suppose you have `Box<Foo>` where Foo is Send but not Sync. (That normally happens with interior mutability, but hypothetically Foo could be something else, like a handle to a resource that uses FFI for something that's only allowed from one thread at a time). Now you can copy the box and move the copies into 2 different threads at once, violating the !Sync guarantees.

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [May 15, 2022, 11:19pm UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/3 "2022-05-15T23:19:06Z")

</div>

First, this is broken in the presence of raw pointers too.

Second, I'm not really convinced by your argument (I can't explain why, but I don't feel good about that).

Third, it is not even decided yet whether you're allowed to access _only the copied from object_ (and it is not invalidated), not to mention _both it and the new object_ ([What about: use-after-move and (maybe) use-after-drop · Issue #188 · rust-lang/unsafe-code-guidelines · GitHub](https://github.com/rust-lang/unsafe-code-guidelines/issues/188)), and [you should avoid doing that in the meantime](https://github.com/rust-lang/unsafe-code-guidelines/issues/307#issuecomment-979591380):

> [@RalfJung](#):
>
> > [@steffahn](#):
> >
> > Overall, this still being an open question means that while miri doesn't complain, one should avoid code like this because it's not yet certain that it won't be UB, right?
> 
> Yes.

Fourth, I think the solution is to (eventually) stabilize auto traits, not create an auto trait in std for each use.

Fifth, this trait already exists (compiler-internal): [`Freeze`](https://doc.rust-lang.org/1.60.0/src/core/marker.rs.html#715).

---

<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:** [May 16, 2022, 8:44am UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/4 "2022-05-16T08:44:42Z")

</div>

> [@chrefr](#):
>
> First, this is broken in the presence of raw pointers too.

How exactly? In copies pointers would point to the same place. It won't work with `Unique<T>` (and so with the `Box<T>`) though, because accessing two copies of `Unique<T>` at the same time would cause problems. But for raw pointers it should be OK.

> [@chrefr](#):
>
> Second, I'm not really convinced by your argument

I guess you can break my argument in multithreaded environment.

> [@chrefr](#):
>
> Third

I'm talking about copies created with `ptr::read` or `ptr::copy`, not by lang's move operation. So no uninitialization could happen.

> [@chrefr](#):
>
> Fourth

That would be too good.

> [@chrefr](#):
>
> Fifth

It can be easier to convince lang teams to make `Freeze` public than creating the trait in the first place. Even if my current use-case is more restricted than I though originally (i.e. it would require `Freeze + Copy + Send` to allow sending copies to other threads).

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [May 16, 2022, 10:07am UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/5 "2022-05-16T10:07:57Z")

</div>

> [@Zakarum](#):
>
> How exactly? In copies pointers would point to the same place. It won't work with `Unique<T>` (and so with the `Box<T>` ) though, because accessing two copies of `Unique<T>` at the same time would cause problems. But for raw pointers it should be OK.

Because they can also be used to mutate. They are, in fact, exterior mutability. Relying on them to not may (and will) break the invariants of types.

> [@Zakarum](#):
>
> I'm talking about copies created with `ptr::read` or `ptr::copy` , not by lang's move operation. So no uninitialization could happen.

This is also discussed in the abovementioned issue.

> [@Zakarum](#):
>
> It can be easier to convince lang teams to make `Freeze` public than creating the trait in the first place. Even if my current use-case is more restricted than I though originally (i.e. it would require `Freeze + Copy + Send` to allow sending copies to other threads).

First, `Freeze` doesn't restrict raw pointers.

Second, I don't really think the lang/libraries teams will be happy to stabilize `Freeze` (quite the contrary), but you can try.

---

<div class="post-metadata">

**Author:** ![comex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/comex/32/2587_2.png) [@comex](https://internals.rust-lang.org/u/comex)\
**Post date:** [May 16, 2022, 7:00pm UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/6 "2022-05-16T19:00:26Z")

</div>

> [@Zakarum](#):
>
> The only other problem I've imaged is that two pointers with different addresses to a value that represents some resource may be considered to point to different resources by some unsafe code.

This is a somewhat common pattern:

> <https://stackoverflow.com/questions/38315383/whats-the-rust-idiom-to-define-a-field-pointing-to-a-c-opaque-pointer>

There are other cases where a type can reference memory addresses beyond its own bounds in unusual ways, that wouldn’t work if the object is copied to a different address:

- A struct that’s expected to only ever exist as a specific field of another, larger struct, so unsafe code expects it can go from one to the other by subtracting an offset from the pointer (search for “container\_of”).
- XOR linked lists.
- Relative pointers. (Ironically, these are usually used as a way to ensure a type _can_ be moved just by copying bytes, assuming the relative pointer points to another part of the same allocation, but it could still be the case that that other part is outside of the object you’re copying. Alternately, a relative pointer might point to some other allocation entirely, which would defeat the usual purpose of using relative pointers, but there might be other reasons for their use.)

In many cases, though not all, these patterns are also incompatible with strict provenance and/or [subobject slicing](https://github.com/rust-lang/unsafe-code-guidelines/issues/134). But there’s a reason there was a backlash against strict provenance: plenty of real code does not follow it.

---

<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:** [May 16, 2022, 9:08pm UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/7 "2022-05-16T21:08:24Z")

</div>

> [@Zakarum](#):
>
> Thus I could add a type bound that restricts safe API only to types that do not have interior mutability, i.e. no `UnsafeCell` among the fields.

Arguably, you might even want to have a weaker condition for your use-case: only ruling out interior mutability that isn't behind at least one indirection. E. g. `Cell<u8>` is problematic but `Box<Cell<u8>>` should be fine again.

---

<div class="post-metadata">

**Author:** ![bascule](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bascule/32/3057_2.png) [@bascule](https://internals.rust-lang.org/u/bascule)\
**Post date:** [May 17, 2022, 12:03am UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/8 "2022-05-17T00:03:45Z")

</div>

I've wanted a feature along these lines as well, but for different use cases.

The main one would be the ability to ensure a value is truly immutable.

Something like this:

```rust
use std::str::{self, Utf8Error};

pub struct Foo<T: AsRef<[u8]> + NoInteriorMutability> {
    inner: T
}

impl Foo<T>
where
    T: AsRef<[u8]> + NoInteriorMutability
{
    /// Precheck that T represents a valid string
    pub fn new(storage: T) -> Result<Self, Utf8Error> {
        // Ensure storage contains valid UTF-8
        str::from_utf8(storage.as_ref())?;
        Ok(Self { inner: storage })
    }
}

impl AsRef<str> for Foo<T>
where
    T: AsRef<[u8]> + NoInteriorMutability
{
    fn as_ref(&self) -> &str {
        // Safety: checked to be valid UTF-8 when constructed.
        // Using unsafe ensures this function is panic-free.
        unsafe { str::from_utf8_unchecked(self.inner.as_ref()) }
    }
}

```

With guaranteed immutability values can be checked in advance that a given conversion is safe, eliminating a potential panic when trying to perform conversions.

---

<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:** [May 17, 2022, 11:21am UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/9 "2022-05-17T11:21:03Z")

</div>

Though that specific example is easily exploited, you need a more stringent promise like `StableDeref` provides

```rust
static STR: &str = "foo";
static NOT_STR: &[u8] = &[0x00, 0xff];

struct Foo;
impl NoInteriorMutability for Foo {}
impl AsRef<[u8]> for Foo {
  fn as_ref(&self) -> &[u8] {
    if rand() { STR.as_bytes() } else { NOT_STR }
  }
}

```

---

<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:** [May 17, 2022, 11:59am UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/10 "2022-05-17T11:59:36Z")

</div>

If value behind a pointer is changed, invariants are not broken since pointer itself is unchanged, so copy points to the same place and changes is visible to it. So raw pointers would be permitted, as well as references and `NonNull<T>`. But not `Unique<T>`, Hence `Freeze` is implemented in exactly the way I'd like, except for `Unique`.

But I understand that some unsafe code may rely on the fact that there's no immutable copies of the value. i.e. there's only one safely accessible address where value is stored. Which is not and should not be covered by `Freeze`.

---

<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:** [May 17, 2022, 12:00pm UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/11 "2022-05-17T12:00:27Z")

</div>

Exactly. That's why I said that all kind pointers should implement it. Except I didn't think of `Unique<T>` at the time.

---

<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:** [May 17, 2022, 12:04pm UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/12 "2022-05-17T12:04:29Z")

</div>

Code you describe requires that value is not moved either. Which is totally safe op unless `Pin` is involved. Which means that I should not copy pinned values. Which is OK, since I was going to require mutable reference or ownership of the value to perform the copies, and that's definitely means it isn't pinned. Unsafe code that takes `&mut T` out of `Pin<&mut T>` should know better than put it into copy machine 🙂

---

<div class="post-metadata">

**Author:** ![chrefr](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@chrefr](https://internals.rust-lang.org/u/chrefr)\
**Post date:** [May 17, 2022, 3:19pm UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/13 "2022-05-17T15:19:43Z")

</div>

While `Unique<T>` is a lang item and has special SB treatment, it still can be viewed as just a pointer. And no one can, or should, prevent unsafe code from making the same invariant, and your code will allow people to break that.

Copying values is such a fundamental operation that unsafe code relies on invariants regarding it a lot; that is why we have `Copy`. Copying things that are not `Copy`, that is, were never meant to be copied and moreover, many times they were meant to _not_ be copied, is going to break a lot of things. If you want a trait for "can be safely duplicated", well, it has the name `Copy`.

Now there can (though I doubt that, since `Copy` is that essential) a type that is mistakenly not `Copy` and you cannot fix it for some reason, make a newtype and unsafely copy it, that's fine (assuming we suppose that's fine, see the above UCG issue). But doing that _generically_ is going to hurt you.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [August 15, 2022, 3:20pm UTC](https://internals.rust-lang.org/t/autotrait-to-mark-types-without-interior-mutability/16636/14 "2022-08-15T15:20:40Z")

</div>

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