Skip to content

BackTraceMarker should be repr(u16), and Component should not be Pod #16

@zachs18

Description

@zachs18

let my_struct_bytes: [u8; std::mem::size_of::<Components>()] = std::mem::transmute(components);

This test invokes UB by producing an invalid value of type u8.

BacktraceMaker is a (implicitly repr(Rust)) fieldless enum, so it's representation is unspecified. In practice, it will be represented as u8, since it has fewer than 256 variants.

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Component {
pub fr: i32,
pub insertion_count: u16,
pub bt: BackTraceMarker,
}

The layout of Component is therefore

  • bytes 0..=3: fr: i32
  • bytes 4..=5: insertion_count: u16
  • byte 6: bt: BackTraceMarker
  • byte 7: padding

Components is effectively [Component; 3], so it therefore also has padding (at bytes 7, 15, and 23)

Since Components has padding, it is UB to transmute it to [u8; _] (and it should not implement bytemuck::Pod)

However, if you add #[repr(u16)] (or #[repr(i16)]) to BacktraceMarker, then Component will not have any padding bytes, so this particular test will no longer invoke UB.

 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[repr(u16)]
 pub enum BackTraceMarker {
     Empty = 0,
     Start = 1,
     FromM = 2,
     FromD = 3,
     FromI = 4,
 }

However, Component still should not implement bytemuck::Pod, which requires that "The type must allow any bit pattern", which is not true since BackTraceMarker only allows the values 0..=4. It could be NoUninit and Zeroable, however.


Found by https://github.com/craterbot at rust-lang/rust#140985 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions