1
Fork 0

fix const align_offset implementation

This commit is contained in:
Lukas Markeffsky 2022-11-15 15:55:37 +01:00
parent 8717455b9d
commit 9e5d497b67
2 changed files with 61 additions and 36 deletions

View file

@ -278,9 +278,8 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
return u64::MAX; return u64::MAX;
} }
let byte_offset = align - addr_mod_align;
if align % stride == 0 { if align % stride == 0 {
let byte_offset = align - addr_mod_align;
if byte_offset % stride == 0 { if byte_offset % stride == 0 {
return byte_offset / stride; return byte_offset / stride;
} else { } else {
@ -296,8 +295,11 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
return u64::MAX; return u64::MAX;
} }
// Instead of `(addr + offset * stride) % align == 0`, we solve
// `((addr + offset * stride) / gcd) % (align / gcd) == 0`.
let addr2 = addr / gcd;
let align2 = align / gcd; let align2 = align / gcd;
let stride2 = (stride / gcd) % align2; let stride2 = stride / gcd;
let mut stride_inv = 1u64; let mut stride_inv = 1u64;
let mut mod_gate = 2u64; let mut mod_gate = 2u64;
@ -308,6 +310,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
(mod_gate, overflow) = mod_gate.overflowing_mul(mod_gate); (mod_gate, overflow) = mod_gate.overflowing_mul(mod_gate);
} }
let byte_offset = align2 - addr2 % align2;
byte_offset.wrapping_mul(stride_inv) % align2 byte_offset.wrapping_mul(stride_inv) % align2
} }

View file

@ -510,49 +510,53 @@ fn align_offset_various_strides_const() {
assert!(got == expected); assert!(got == expected);
} }
// For pointers of stride != 1, we verify the algorithm against the naivest possible const {
// implementation // For pointers of stride != 1, we verify the algorithm against the naivest possible
let mut align = 1; // implementation
let limit = 1024; let mut align = 1;
while align < limit { let limit = 32;
for ptr in 1usize..4 * align { while align < limit {
unsafe { let mut ptr = 1;
#[repr(packed)] while ptr < 4 * align {
struct A3(u16, u8); unsafe {
test_stride::<A3>(ptr::invalid::<A3>(ptr), ptr, align); #[repr(packed)]
struct A3(u16, u8);
test_stride::<A3>(ptr::invalid::<A3>(ptr), ptr, align);
struct A4(u32); struct A4(u32);
test_stride::<A4>(ptr::invalid::<A4>(ptr), ptr, align); test_stride::<A4>(ptr::invalid::<A4>(ptr), ptr, align);
#[repr(packed)] #[repr(packed)]
struct A5(u32, u8); struct A5(u32, u8);
test_stride::<A5>(ptr::invalid::<A5>(ptr), ptr, align); test_stride::<A5>(ptr::invalid::<A5>(ptr), ptr, align);
#[repr(packed)] #[repr(packed)]
struct A6(u32, u16); struct A6(u32, u16);
test_stride::<A6>(ptr::invalid::<A6>(ptr), ptr, align); test_stride::<A6>(ptr::invalid::<A6>(ptr), ptr, align);
#[repr(packed)] #[repr(packed)]
struct A7(u32, u16, u8); struct A7(u32, u16, u8);
test_stride::<A7>(ptr::invalid::<A7>(ptr), ptr, align); test_stride::<A7>(ptr::invalid::<A7>(ptr), ptr, align);
#[repr(packed)] #[repr(packed)]
struct A8(u32, u32); struct A8(u32, u32);
test_stride::<A8>(ptr::invalid::<A8>(ptr), ptr, align); test_stride::<A8>(ptr::invalid::<A8>(ptr), ptr, align);
#[repr(packed)] #[repr(packed)]
struct A9(u32, u32, u8); struct A9(u32, u32, u8);
test_stride::<A9>(ptr::invalid::<A9>(ptr), ptr, align); test_stride::<A9>(ptr::invalid::<A9>(ptr), ptr, align);
#[repr(packed)] #[repr(packed)]
struct A10(u32, u32, u16); struct A10(u32, u32, u16);
test_stride::<A10>(ptr::invalid::<A10>(ptr), ptr, align); test_stride::<A10>(ptr::invalid::<A10>(ptr), ptr, align);
test_stride::<u32>(ptr::invalid::<u32>(ptr), ptr, align); test_stride::<u32>(ptr::invalid::<u32>(ptr), ptr, align);
test_stride::<u128>(ptr::invalid::<u128>(ptr), ptr, align); test_stride::<u128>(ptr::invalid::<u128>(ptr), ptr, align);
}
ptr += 1;
} }
align = (align + 1).next_power_of_two();
} }
align = (align + 1).next_power_of_two();
} }
} }
@ -632,6 +636,24 @@ fn align_offset_issue_103361() {
let _ = (SIZE as *const HugeSize).align_offset(SIZE); let _ = (SIZE as *const HugeSize).align_offset(SIZE);
} }
#[test]
#[cfg(not(bootstrap))]
fn align_offset_issue_103361_const() {
#[cfg(target_pointer_width = "64")]
const SIZE: usize = 1 << 47;
#[cfg(target_pointer_width = "32")]
const SIZE: usize = 1 << 30;
#[cfg(target_pointer_width = "16")]
const SIZE: usize = 1 << 13;
struct HugeSize([u8; SIZE - 1]);
const {
assert!(ptr::invalid::<HugeSize>(SIZE - 1).align_offset(SIZE) == SIZE - 1);
assert!(ptr::invalid::<HugeSize>(SIZE).align_offset(SIZE) == 0);
assert!(ptr::invalid::<HugeSize>(SIZE + 1).align_offset(SIZE) == 1);
}
}
#[test] #[test]
fn is_aligned() { fn is_aligned() {
let data = 42; let data = 42;