blob: d27804084d73d078ff56e3d2c63064d25063d273 [file] [log] [blame] [edit]
//! Test that various operations involving pointer fragments work as expected.
//@ run-pass
use std::mem::{self, MaybeUninit, transmute};
use std::ptr;
type Byte = MaybeUninit<u8>;
const unsafe fn memcpy(dst: *mut Byte, src: *const Byte, n: usize) {
let mut i = 0;
while i < n {
*dst.add(i) = *src.add(i);
i += 1;
}
}
const _MEMCPY: () = unsafe {
let ptr = &42;
let mut ptr2 = ptr::null::<i32>();
memcpy(&mut ptr2 as *mut _ as *mut _, &ptr as *const _ as *const _, mem::size_of::<&i32>());
assert!(*ptr2 == 42);
};
const _MEMCPY_OFFSET: () = unsafe {
// Same as above, but the pointer has a non-zero offset so not all the data bytes are the same.
let ptr = &(42, 18);
let ptr = &ptr.1;
let mut ptr2 = ptr::null::<i32>();
memcpy(&mut ptr2 as *mut _ as *mut _, &ptr as *const _ as *const _, mem::size_of::<&i32>());
assert!(*ptr2 == 18);
};
const MEMCPY_RET: MaybeUninit<*const i32> = unsafe {
let ptr = &42;
let mut ptr2 = MaybeUninit::new(ptr::null::<i32>());
memcpy(&mut ptr2 as *mut _ as *mut _, &ptr as *const _ as *const _, mem::size_of::<&i32>());
// Return in a MaybeUninit so it does not get treated as a scalar.
ptr2
};
#[allow(dead_code)]
fn reassemble_ptr_fragments_in_static() {
static DATA: i32 = 1i32;
#[cfg(target_pointer_width = "64")]
struct Thing {
x: MaybeUninit<u32>,
y: MaybeUninit<u32>,
}
#[cfg(target_pointer_width = "32")]
struct Thing {
x: MaybeUninit<u16>,
y: MaybeUninit<u16>,
}
static X: Thing = unsafe {
let Thing { x, y } = transmute(&raw const DATA);
Thing { x, y }
};
}
const _PARTIAL_OVERWRITE: () = {
// The result in `p` is not a valid pointer, but we never use it again so that's fine.
let mut p = &42;
unsafe {
let ptr: *mut _ = &mut p;
*(ptr as *mut u8) = 123;
}
};
#[allow(dead_code)]
#[cfg(not(target_arch = "s390x"))] // u128 is less aligned on s390x, removing the padding
fn fragment_in_dst_padding_gets_overwritten() {
#[repr(C)]
struct Pair {
x: u128,
// at offset 16
y: u64,
}
const C: MaybeUninit<Pair> = unsafe {
let mut m = MaybeUninit::<Pair>::uninit();
// Store pointer half-way into trailing padding.
m.as_mut_ptr().byte_add(20).cast::<&i32>().write_unaligned(&0);
// Overwrite `m`.
let val = Pair { x: 0, y: 0 };
*m.as_mut_ptr() = val;
// If the assignment of `val` above only copied the field and left the rest of `m`
// unchanged, there would be pointer fragments left in the padding which would be carried
// all the way to the final value, causing compilation failure.
// We prevent this by having the copy of `val` overwrite the entire destination.
m
};
}
fn main() {
assert_eq!(unsafe { MEMCPY_RET.assume_init().read() }, 42);
}