Pre-RFC: #[single_repr] attribute for ADTs


#1

Motivation

Currently, all ADTs in Rust have undef padding. This means that each particular value of an ADT may be represented in many ways as a bit-pattern.

This forms a problem for 2 reasons

  • The bit-pattern of an ADT can’t be used as a key in maps, because multiple such values might exist.
  • The ADT can’t be used for “memcpy serialization”, because that would leak potentially-sensitive stack data.

These problems can’t easily be bypassed - because padding is always treated as undef, merely moving an ADT rerandomizes the padding. You have to write a potentially-expensive translation function, which has to branch on the variant in the case of an enum.

Design

Add a #[single_repr] attribute to ADTs.

#[single_repr]
struct Foo { .. }

#[single_repr]
enum Foo { .. }

#[single_repr]
union Foo { .. }

An ADT with a #[single_repr] has a single bit-pattern for each series of bit-patterns for fields. For #[repr(C)], this is defined to be the bit-pattern with all padding 0.

Loading (that looks like a better name for my VExpr::Use, bikeshed) a value of that ADT with a non-canonical bitpattern is UB.

Of course, if one of the fields has multiple bit-patterns, that would be preserved. We should have a lint against that.


#2

#[no_padding]/#[effortless_packing] might also be useful to assert the same property on hand-packed structs, while avoiding the cost of initializing padding to a known value.


#3

I don’t have an opinion on the proposal itself, but can we please call the attribute unique_repr? IMHO that captures its, well, uniqueness much better. :wink:


#4

Would there be a way to have a compiler generated function (intrinsic) that takes a slice, returns an Ok(value) iff the slice’s bytes contain the correct bit patterns. This function should obviously only exist for Copy types.

Without such a function in the standard lib, I’d fear ppl would start writing their own without any checks.

Also, to be able to optimize (specialize) generic datastructures for unique_repr types, how about these types automatically implement a marker trait?


#5

Structures can contain things like references, so loading them out of a byte-buffer is certainly unsafe. However, an

extern "Rust" fn verify_adt<T>(adt: *const T) -> bool;

that verifies an ADT is certainly a possibility, if there is sufficient demand.