Skip to content

Validity of raw pointers #75

@RalfJung

Description

@RalfJung
Member

Discussing the validity invariant of raw pointers.

For pointers to sized types, this should probably be the same as the invariant for usize -- see the integer topic for discussing whether uninitialized bits are allowed or not.

For pointers to unsized types, there is an additional question: to what extent does the metadata have to be initialized/valid? Do we require it to be "valid" enough to determine size and alignment, e.g. do we require that the vtable pointer actually point to allocated memory?

Activity

nikomatsakis

nikomatsakis commented on Jan 31, 2019

@nikomatsakis
Contributor

For pointers to sized types, this should probably be the same as the invariant for usize -- see the integer topic for discussing whether uninitialized bits are allowed or not.

Agreed, I think a cast from raw pointer to usize (and vice versa) should not be UB.

There is an additional question: to what extent does the metadata have to be initialized/valid? Do we require it to be "valid" enough to determine size and alignment, e.g. do we require that the vtable pointer actually point to allocated memory?

This is worth drilling a bit more into. I know I've had conversations with @eddyb, @Manishearth, @withoutboats, and a few others about this, and I'd love to hear more from them.

I believe that @Manishearth's argument boiled down to "it's really useful to be able to create the equivalent of a NULL pointer: a kind of 'universally valid' value that you know will be overwritten before the reference is ultimately used". I find this a compelling argument: we should make sure we can support that. I suppose the answer is that you can use MaybeUninit, though that definitely comes at an ergonomic cost.

I think it's certainly an option to say that the "metadata must always be valid". It'd be good to drill into the reasons we might want this to be true. Perhaps it's helpful to list out the times we need metadata to be valid?

Some examples I can think of:

  • Computing the alignment of a particular reference
  • Figuring out the offset of fields in a struct (that can depend on the alignment)
  • Invoking methods from a trait (particularly once we support fn foo(*mut self) methods, which are presently blocked on resolving this discussion)

Mostly these do seem to be tied to discrete actions in the code, though, and hence point to an invariant that could be enforced at the point of use.

Amanieu

Amanieu commented on Jan 31, 2019

@Amanieu
Member

Mostly these do seem to be tied to discrete actions in the code, though, and hence point to an invariant that could be enforced at the point of use.

I would argue that since all of these examples require references, valid metadata should only be needed for references while raw pointers (as long as they are not dereferenced) would be allowed to have invalid/null metadata.

Are there any cases where we need to access the metadata of a raw pointer without first turning it into a reference?

SimonSapin

SimonSapin commented on Jan 31, 2019

@SimonSapin

I think @RalfJung mentioned before we could/should have variants of mem::size_of_val and mem::align_of_val that take a raw pointer instead of a reference, for example for use in Box’s destructor https://github.com/rust-lang/rust/blob/8a0e5faec7f62e3cfd88d6625ce213d93b061305/src/liballoc/alloc.rs#L195-L196

gnzlbg

gnzlbg commented on Feb 4, 2019

@gnzlbg
Contributor

If we accept uninitialized bits as being a valid representation for usize, I wonder how that would impact what valid means for thin raw pointers and raw pointers in general. It might be weird to say that *mut i32 can be uninitialized, but that *mut dyn Trait cannot (or at least that some part of it cannot be, like e.g. the pointer to the vtable). We would be adding another rule that's not simple: instead of it being all raw pointers can / can't be uninitialized, we are adding a rule of the form: "some" raw pointers can be uninitialized.

Amanieu

Amanieu commented on Feb 4, 2019

@Amanieu
Member

It makes sense if you consider that we are only keeping mem::uninitialized valid for a limited set of types to maintain backwards compatibility with existing code. The majority of uses of mem::uninitialized are used with C structs which are then initialized through an FFI call, where fat pointers will not be used.

RalfJung

RalfJung commented on Feb 5, 2019

@RalfJung
MemberAuthor

I assume if we allow uninitialized integers, we will also allow uninitialized data in the metadata of a raw pointer. I see no harm in that.

JakobDegen

JakobDegen commented on Jun 6, 2023

@JakobDegen
Contributor

Closing, partially answered partially in favor of #166

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-validityTopic: Related to validity invariants

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @nikomatsakis@Amanieu@SimonSapin@RalfJung@gnzlbg

        Issue actions

          Validity of raw pointers · Issue #75 · rust-lang/unsafe-code-guidelines