add some interesting tests for alignment corner cases
This commit is contained in:
parent
e1071af908
commit
a63db6de5a
@ -0,0 +1,24 @@
|
||||
/// This tests that when a field sits at offset 0 in a 4-aligned struct, accessing the field
|
||||
/// requires alignment 4 even if the field type has lower alignment requirements.
|
||||
|
||||
#[repr(C)]
|
||||
pub struct S {
|
||||
x: u8,
|
||||
y: u32,
|
||||
}
|
||||
|
||||
unsafe fn foo(x: *const S) -> u8 {
|
||||
unsafe { (*x).x } //~ERROR: accessing memory with alignment 1, but alignment 4 is required
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let mem = [0u64; 16];
|
||||
let odd_ptr = std::ptr::addr_of!(mem).cast::<u8>().add(1);
|
||||
// `odd_ptr` is now not aligned enough for `S`.
|
||||
// If accessing field `x` can exploit that it is at offset 0
|
||||
// in a 4-aligned struct, that field access requires alignment 4,
|
||||
// thus making this UB.
|
||||
foo(odd_ptr.cast());
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
|
||||
--> $DIR/field_requires_parent_struct_alignment.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { (*x).x }
|
||||
| ^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `foo` at $DIR/field_requires_parent_struct_alignment.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> $DIR/field_requires_parent_struct_alignment.rs:LL:CC
|
||||
|
|
||||
LL | foo(odd_ptr.cast());
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,23 @@
|
||||
#![allow(unused)]
|
||||
|
||||
#[repr(u16)]
|
||||
enum DeviceKind {
|
||||
Nil = 0,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct DeviceInfo {
|
||||
endianness: u8,
|
||||
device_kind: DeviceKind,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// The layout of `Option<(DeviceInfo, u64)>` is funny: it uses the
|
||||
// `DeviceKind` enum as niche, so that is offset 1, but the niche type is u16!
|
||||
// So despite the type having alignment 8 and the field type alignment 2,
|
||||
// the actual alignment is 1.
|
||||
let x = None::<(DeviceInfo, u8)>;
|
||||
let y = None::<(DeviceInfo, u16)>;
|
||||
let z = None::<(DeviceInfo, u64)>;
|
||||
format!("{} {} {}", x.is_some(), y.is_some(), y.is_some());
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#[repr(u16)]
|
||||
#[allow(dead_code)]
|
||||
enum DeviceKind {
|
||||
Nil = 0,
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
#[allow(dead_code)]
|
||||
struct DeviceInfo {
|
||||
endianness: u8,
|
||||
device_kind: DeviceKind,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _x = None::<(DeviceInfo, u8)>;
|
||||
let _y = None::<(DeviceInfo, u16)>;
|
||||
let _z = None::<(DeviceInfo, u64)>;
|
||||
}
|
Loading…
Reference in New Issue
Block a user