# Should pointer methods/functions accept !Sized?

**URL:** https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166
**Category:** libs
**Created:** [August 9, 2018, 5:17pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166 "2018-08-09T17:17:04Z")
**Posts on this page:** 18
**Page:** 1

<div class="post-metadata">

### Author: ![joshlf](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/joshlf/32/3815_2.png) [@joshlf](https://internals.rust-lang.org/u/joshlf)
#### Post date: [August 9, 2018, 5:17pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/1 "2018-08-09T17:17:05Z")

</div>

As discussed in [this recent RFC](https://github.com/rust-lang/rfcs/pull/2521), `ptr::null` and `ptr::null_mut` have a `T: Sized` bound. Is there a good reason we can’t remove this bound, making the bound `T: ?Sized`? I propose that we update these functions to take a `T: ?Sized`. All other functions/types in the `ptr` module that do not require size (`eq`, `NonNull`, etc) have a `T: ?Sized` bound.

If folks agree, I can put up a PR.

---

<div class="post-metadata">

### Author: ![dtolnay](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dtolnay/32/1447_2.png) [@dtolnay](https://internals.rust-lang.org/u/dtolnay)
#### Post date: [August 9, 2018, 5:27pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/2 "2018-08-09T17:27:15Z")

</div>

Currently it is UB to have a null vtable pointer, it’s as if `*mut Trait` and `&mut Trait` / `Box<Trait>` all have the same safe `&'static VtableForTrait` pointer as the fat metadata.

In the case of:

```rust
trait MyTrait {}

fn main() {
    std::ptr::null::<MyTrait>();
}

```

there is no legal vtable that `ptr::null` could place in the pointer.

---

<div class="post-metadata">

### Author: ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)
#### Post date: [August 9, 2018, 5:48pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/3 "2018-08-09T17:48:57Z")

</div>

This concept also came up in [pr44932](https://github.com/rust-lang/rust/pull/44932) when I wanted to unsize `is_null()`, and that was later re-added in [pr46094](https://github.com/rust-lang/rust/pull/46094) citing the discussion in [rfcs#433](https://github.com/rust-lang/rfcs/issues/433). Checking for null is a simpler question than producing it though.

---

<div class="post-metadata">

### Author: ![SimonSapin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simonsapin/32/3158_2.png) [@SimonSapin](https://internals.rust-lang.org/u/SimonSapin)
#### Post date: [August 9, 2018, 5:50pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/4 "2018-08-09T17:50:16Z")

</div>

Not having a vtable pointer as @dtolnay explained is why simply adding `T: ?Sized` is rejected by the compiler:

```rust
error[E0606]: casting `usize` as `*const T` is invalid
 --> a.rs:1:36
  |
1 | fn null<T: ?Sized>() -> *const T { 0 as *const T }
  | ^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0606`.

```

---

<div class="post-metadata">

### Author: ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://internals.rust-lang.org/u/vitalyd)
#### Post date: [August 9, 2018, 5:55pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/5 "2018-08-09T17:55:46Z")

</div>

Perhaps `null()` (and `null_mut()`) should be (based on) compiler intrinsics/builtins; the compiler can then fill in a valid vtbl ptr for a trait object and, more generally, fabricate a valid (but null) ptr to any `T`.

---

<div class="post-metadata">

### Author: ![dtolnay](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dtolnay/32/1447_2.png) [@dtolnay](https://internals.rust-lang.org/u/dtolnay)
#### Post date: [August 9, 2018, 6:11pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/6 "2018-08-09T18:11:17Z")

</div>

@vitalyd I don’t know how a compiler intrinsic/builtin would make a difference. The compiler cannot invent an implementation of the trait to use for null pointers, for example in:

```rust
#![feature(arbitrary_self_types)]

trait TypeName {
    fn type_name(self: *const Self) -> &'static str;
}

fn main() {
    println!("{}", std::ptr::null::<dyn TypeName>().type_name());
}

```

---

<div class="post-metadata">

### Author: ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://internals.rust-lang.org/u/vitalyd)
#### Post date: [August 9, 2018, 6:13pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/7 "2018-08-09T18:13:49Z")

</div>

> [@dtolnay](#):
>
> @vitalyd I don’t know how a compiler intrinsic/builtin would make a difference. The compiler cannot invent an implementation of the trait to use for null pointers

Why not? AFAIK, there's no guarantee about a vtbl being the same even for the same impl (due to CGU differences) so I can't immediately see a reason why it couldn't fabricate something as it sees fit.

---

<div class="post-metadata">

### Author: ![dtolnay](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dtolnay/32/1447_2.png) [@dtolnay](https://internals.rust-lang.org/u/dtolnay)
#### Post date: [August 9, 2018, 6:15pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/8 "2018-08-09T18:15:38Z")

</div>

What string would you expect the code in my previous comment to print?

---

<div class="post-metadata">

### Author: ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://internals.rust-lang.org/u/vitalyd)
#### Post date: [August 9, 2018, 6:16pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/9 "2018-08-09T18:16:31Z")

</div>

That would be UB since the ptr is null? So in some sense, it’s like a form of `!` - it can pretend to be anything since all you can really do, safely, is check for nullness.

---

<div class="post-metadata">

### Author: ![dtolnay](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dtolnay/32/1447_2.png) [@dtolnay](https://internals.rust-lang.org/u/dtolnay)
#### Post date: [August 9, 2018, 6:29pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/10 "2018-08-09T18:29:56Z")

</div>

It would be quite unfortunate for that to be UB because it is 100% safe code. A `ptr.type_name()` is equivalent to `(ptr.vtable.type_name)(ptr.data)` and should work fine for a null data pointer. But as I commented previously, the UB comes from constructing a fat pointer containing a null vtable pointer.

---

<div class="post-metadata">

### Author: ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://internals.rust-lang.org/u/vitalyd)
#### Post date: [August 9, 2018, 6:36pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/11 "2018-08-09T18:36:20Z")

</div>

> [@dtolnay](#):
>
> It would be quite unfortunate for that to be UB because it is 100% safe code. A `ptr.type_name()` is equivalent to `(ptr.vtable.type_name)(ptr.data)` and should work fine for a null data pointer. But as I commented previously, the UB comes from constructing a fat pointer containing a null vtable pointer.

Perhaps my understanding of method calls is wrong, but I was under the impression that you essentially dereference the self as part of the call - the `this` (so to speak) receiver has to be valid, even if you don't use any state from it in the callee. In that, you'd be deref'ing null data ptr, which would be UB.

But your comment implies that my understanding is wrong.

---

<div class="post-metadata">

### Author: ![dtolnay](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dtolnay/32/1447_2.png) [@dtolnay](https://internals.rust-lang.org/u/dtolnay)
#### Post date: [August 9, 2018, 6:41pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/12 "2018-08-09T18:41:00Z")

</div>

In that code the pointer is not dereferenced, it is passed to the trait method as a pointer.

Here is a simpler (safe, compilable) example.

```rust
#![feature(arbitrary_self_types)]

trait MyTrait {
    fn f(self: *const Self);
}

impl MyTrait for u8 {
    fn f(self: *const Self) {
        println!("ptr={:p}", self);
    }
}

fn main() {
    let ptr = 0x3039 as *const u8 as *const MyTrait;
    ptr.f();
}

```

---

<div class="post-metadata">

### Author: ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://internals.rust-lang.org/u/vitalyd)
#### Post date: [August 9, 2018, 6:47pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/13 "2018-08-09T18:47:01Z")

</div>

I understand the pointer is not actually dereferenced - my impression was that the ptr has to be valid as-if it was dereferenced.

In some OO language, a method call involves passing a `this` ptr as a hidden parameter; whether the parameter must be non-null or not is a lang design decision. I’m aware of `arbitrary_self_types` but I’m not sure what guarantees/restrictions it carries, such as in this case: is `*const Self` allowed to be null? Your responses indicate yes. Is that mentioned/documented somewhere? Or does it merely fall out of raw ptrs being allowed to be null and therefore arbitrary self types just “inherit” that?

Also, suppose arbitrary self types were out of the picture or required that self raw ptrs are not null (for sake of argument). Are there other reasons the compiler couldn’t fabricate a vtbl ptr?

At the end of the day, it seems odd that it’s so difficult to fabricate a null ptr, generically. The compiler, in a lot of ways, is likely best positioned to provide that facility (somehow - how exactly, I guess that’s what this thread is about at this point 🙂).

---

<div class="post-metadata">

### Author: ![joshlf](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/joshlf/32/3815_2.png) [@joshlf](https://internals.rust-lang.org/u/joshlf)
#### Post date: [August 9, 2018, 6:51pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/14 "2018-08-09T18:51:35Z")

</div>

Is there a reason that calling a method on a raw pointer (even if that method is safe) shouldn’t always be unsafe? If it were, then we could say that it was the caller’s responsibility to ensure that the pointer was valid. That would, in turn, allow a fat pointer with both the data and vtable pointers as NULL to be a valid (if not valid to dereference) pointer.

---

<div class="post-metadata">

### Author: ![vitalyd](https://avatars.discourse-cdn.com/v4/letter/v/edb3f5/32.png) [@vitalyd](https://internals.rust-lang.org/u/vitalyd)
#### Post date: [August 9, 2018, 7:08pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/15 "2018-08-09T19:08:01Z")

</div>

> [@joshlf](#):
>
> That would, in turn, allow a fat pointer with both the data and vtable pointers as NULL to be a valid (if not valid to dereference) pointer.

FWIW, this part seems risky because there may be unsafe code relying on vtbl ptrs not being null when it, e.g., deconstructs a fat ptr.

---

<div class="post-metadata">

### Author: ![mikeyhew](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mikeyhew/32/2270_2.png) [@mikeyhew](https://internals.rust-lang.org/u/mikeyhew)
#### Post date: [August 9, 2018, 7:10pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/16 "2018-08-09T19:10:23Z")

</div>

It’s one of the guarantees of Rust that a vtable will always be valid. `Option<*const dyn Trait>` is the same size as `*const dyn Trait`, so if you want something similar to a raw pointer with an invalid vtable, you can use `Option::None`.

EDIT: that is at least the case today, maybe we need an RFC to make this an official guarantee

---

<div class="post-metadata">

### Author: ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)
#### Post date: [August 9, 2018, 7:22pm UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/17 "2018-08-09T19:22:27Z")

</div>

I’m not sure what wins this gives us; slice pointers `*const [T]` can be assembled manually, and being able to produce sketchy null pointers to fancy DSTs (imagine something more delicate than a vtable!) is _actually_ unsafe! Think of the reason why `slice::from_raw_parts` is unsafe; I think this is a rare situation where the metadata actually has a safe default (`len: 0`).

---

<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: [March 25, 2019, 8:30am UTC](https://internals.rust-lang.org/t/should-pointer-methods-functions-accept-sized/8166/18 "2019-03-25T08:30:40Z")

</div>

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