rust/library/core/tests/ptr.rs
2020-07-27 19:51:13 -05:00

404 lines
11 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use core::cell::RefCell;
use core::ptr::*;
#[test]
fn test_const_from_raw_parts() {
const SLICE: &[u8] = &[1, 2, 3, 4];
const FROM_RAW: &[u8] = unsafe { &*slice_from_raw_parts(SLICE.as_ptr(), SLICE.len()) };
assert_eq!(SLICE, FROM_RAW);
let slice = &[1, 2, 3, 4, 5];
let from_raw = unsafe { &*slice_from_raw_parts(slice.as_ptr(), 2) };
assert_eq!(&slice[..2], from_raw);
}
#[test]
fn test() {
unsafe {
struct Pair {
fst: isize,
snd: isize,
};
let mut p = Pair { fst: 10, snd: 20 };
let pptr: *mut Pair = &mut p;
let iptr: *mut isize = pptr as *mut isize;
assert_eq!(*iptr, 10);
*iptr = 30;
assert_eq!(*iptr, 30);
assert_eq!(p.fst, 30);
*pptr = Pair { fst: 50, snd: 60 };
assert_eq!(*iptr, 50);
assert_eq!(p.fst, 50);
assert_eq!(p.snd, 60);
let v0 = vec![32000u16, 32001u16, 32002u16];
let mut v1 = vec![0u16, 0u16, 0u16];
copy(v0.as_ptr().offset(1), v1.as_mut_ptr().offset(1), 1);
assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16));
copy(v0.as_ptr().offset(2), v1.as_mut_ptr(), 1);
assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16));
copy(v0.as_ptr(), v1.as_mut_ptr().offset(2), 1);
assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16));
}
}
#[test]
fn test_is_null() {
let p: *const isize = null();
assert!(p.is_null());
let q = p.wrapping_offset(1);
assert!(!q.is_null());
let mp: *mut isize = null_mut();
assert!(mp.is_null());
let mq = mp.wrapping_offset(1);
assert!(!mq.is_null());
// Pointers to unsized types -- slices
let s: &mut [u8] = &mut [1, 2, 3];
let cs: *const [u8] = s;
assert!(!cs.is_null());
let ms: *mut [u8] = s;
assert!(!ms.is_null());
let cz: *const [u8] = &[];
assert!(!cz.is_null());
let mz: *mut [u8] = &mut [];
assert!(!mz.is_null());
let ncs: *const [u8] = null::<[u8; 3]>();
assert!(ncs.is_null());
let nms: *mut [u8] = null_mut::<[u8; 3]>();
assert!(nms.is_null());
// Pointers to unsized types -- trait objects
let ci: *const dyn ToString = &3;
assert!(!ci.is_null());
let mi: *mut dyn ToString = &mut 3;
assert!(!mi.is_null());
let nci: *const dyn ToString = null::<isize>();
assert!(nci.is_null());
let nmi: *mut dyn ToString = null_mut::<isize>();
assert!(nmi.is_null());
}
#[test]
fn test_as_ref() {
unsafe {
let p: *const isize = null();
assert_eq!(p.as_ref(), None);
let q: *const isize = &2;
assert_eq!(q.as_ref().unwrap(), &2);
let p: *mut isize = null_mut();
assert_eq!(p.as_ref(), None);
let q: *mut isize = &mut 2;
assert_eq!(q.as_ref().unwrap(), &2);
// Lifetime inference
let u = 2isize;
{
let p = &u as *const isize;
assert_eq!(p.as_ref().unwrap(), &2);
}
// Pointers to unsized types -- slices
let s: &mut [u8] = &mut [1, 2, 3];
let cs: *const [u8] = s;
assert_eq!(cs.as_ref(), Some(&*s));
let ms: *mut [u8] = s;
assert_eq!(ms.as_ref(), Some(&*s));
let cz: *const [u8] = &[];
assert_eq!(cz.as_ref(), Some(&[][..]));
let mz: *mut [u8] = &mut [];
assert_eq!(mz.as_ref(), Some(&[][..]));
let ncs: *const [u8] = null::<[u8; 3]>();
assert_eq!(ncs.as_ref(), None);
let nms: *mut [u8] = null_mut::<[u8; 3]>();
assert_eq!(nms.as_ref(), None);
// Pointers to unsized types -- trait objects
let ci: *const dyn ToString = &3;
assert!(ci.as_ref().is_some());
let mi: *mut dyn ToString = &mut 3;
assert!(mi.as_ref().is_some());
let nci: *const dyn ToString = null::<isize>();
assert!(nci.as_ref().is_none());
let nmi: *mut dyn ToString = null_mut::<isize>();
assert!(nmi.as_ref().is_none());
}
}
#[test]
fn test_as_mut() {
unsafe {
let p: *mut isize = null_mut();
assert!(p.as_mut() == None);
let q: *mut isize = &mut 2;
assert!(q.as_mut().unwrap() == &mut 2);
// Lifetime inference
let mut u = 2isize;
{
let p = &mut u as *mut isize;
assert!(p.as_mut().unwrap() == &mut 2);
}
// Pointers to unsized types -- slices
let s: &mut [u8] = &mut [1, 2, 3];
let ms: *mut [u8] = s;
assert_eq!(ms.as_mut(), Some(&mut [1, 2, 3][..]));
let mz: *mut [u8] = &mut [];
assert_eq!(mz.as_mut(), Some(&mut [][..]));
let nms: *mut [u8] = null_mut::<[u8; 3]>();
assert_eq!(nms.as_mut(), None);
// Pointers to unsized types -- trait objects
let mi: *mut dyn ToString = &mut 3;
assert!(mi.as_mut().is_some());
let nmi: *mut dyn ToString = null_mut::<isize>();
assert!(nmi.as_mut().is_none());
}
}
#[test]
fn test_ptr_addition() {
unsafe {
let xs = vec![5; 16];
let mut ptr = xs.as_ptr();
let end = ptr.offset(16);
while ptr < end {
assert_eq!(*ptr, 5);
ptr = ptr.offset(1);
}
let mut xs_mut = xs;
let mut m_ptr = xs_mut.as_mut_ptr();
let m_end = m_ptr.offset(16);
while m_ptr < m_end {
*m_ptr += 5;
m_ptr = m_ptr.offset(1);
}
assert!(xs_mut == vec![10; 16]);
}
}
#[test]
fn test_ptr_subtraction() {
unsafe {
let xs = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut idx = 9;
let ptr = xs.as_ptr();
while idx >= 0 {
assert_eq!(*(ptr.offset(idx as isize)), idx as isize);
idx = idx - 1;
}
let mut xs_mut = xs;
let m_start = xs_mut.as_mut_ptr();
let mut m_ptr = m_start.offset(9);
loop {
*m_ptr += *m_ptr;
if m_ptr == m_start {
break;
}
m_ptr = m_ptr.offset(-1);
}
assert_eq!(xs_mut, [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
}
}
#[test]
fn test_set_memory() {
let mut xs = [0u8; 20];
let ptr = xs.as_mut_ptr();
unsafe {
write_bytes(ptr, 5u8, xs.len());
}
assert!(xs == [5u8; 20]);
}
#[test]
fn test_unsized_nonnull() {
let xs: &[i32] = &[1, 2, 3];
let ptr = unsafe { NonNull::new_unchecked(xs as *const [i32] as *mut [i32]) };
let ys = unsafe { ptr.as_ref() };
let zs: &[i32] = &[1, 2, 3];
assert!(ys == zs);
}
#[test]
#[allow(warnings)]
// Have a symbol for the test below. It doesnt need to be an actual variadic function, match the
// ABI, or even point to an actual executable code, because the function itself is never invoked.
#[no_mangle]
pub fn test_variadic_fnptr() {
use core::hash::{Hash, SipHasher};
extern "C" {
fn test_variadic_fnptr(_: u64, ...) -> f64;
}
let p: unsafe extern "C" fn(u64, ...) -> f64 = test_variadic_fnptr;
let q = p.clone();
assert_eq!(p, q);
assert!(!(p < q));
let mut s = SipHasher::new();
assert_eq!(p.hash(&mut s), q.hash(&mut s));
}
#[test]
fn write_unaligned_drop() {
thread_local! {
static DROPS: RefCell<Vec<u32>> = RefCell::new(Vec::new());
}
struct Dropper(u32);
impl Drop for Dropper {
fn drop(&mut self) {
DROPS.with(|d| d.borrow_mut().push(self.0));
}
}
{
let c = Dropper(0);
let mut t = Dropper(1);
unsafe {
write_unaligned(&mut t, c);
}
}
DROPS.with(|d| assert_eq!(*d.borrow(), [0]));
}
#[test]
#[cfg_attr(miri, ignore)] // Miri does not compute a maximal `mid` for `align_offset`
fn align_offset_zst() {
// For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at
// all, because no amount of elements will align the pointer.
let mut p = 1;
while p < 1024 {
assert_eq!((p as *const ()).align_offset(p), 0);
if p != 1 {
assert_eq!(((p + 1) as *const ()).align_offset(p), !0);
}
p = (p + 1).next_power_of_two();
}
}
#[test]
#[cfg_attr(miri, ignore)] // Miri does not compute a maximal `mid` for `align_offset`
fn align_offset_stride1() {
// For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
// number of bytes.
let mut align = 1;
while align < 1024 {
for ptr in 1..2 * align {
let expected = ptr % align;
let offset = if expected == 0 { 0 } else { align - expected };
assert_eq!(
(ptr as *const u8).align_offset(align),
offset,
"ptr = {}, align = {}, size = 1",
ptr,
align
);
}
align = (align + 1).next_power_of_two();
}
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn align_offset_weird_strides() {
#[repr(packed)]
struct A3(u16, u8);
struct A4(u32);
#[repr(packed)]
struct A5(u32, u8);
#[repr(packed)]
struct A6(u32, u16);
#[repr(packed)]
struct A7(u32, u16, u8);
#[repr(packed)]
struct A8(u32, u32);
#[repr(packed)]
struct A9(u32, u32, u8);
#[repr(packed)]
struct A10(u32, u32, u16);
unsafe fn test_weird_stride<T>(ptr: *const T, align: usize) -> bool {
let numptr = ptr as usize;
let mut expected = usize::MAX;
// Naive but definitely correct way to find the *first* aligned element of stride::<T>.
for el in 0..align {
if (numptr + el * ::std::mem::size_of::<T>()) % align == 0 {
expected = el;
break;
}
}
let got = ptr.align_offset(align);
if got != expected {
eprintln!(
"aligning {:p} (with stride of {}) to {}, expected {}, got {}",
ptr,
::std::mem::size_of::<T>(),
align,
expected,
got
);
return true;
}
return false;
}
// For pointers of stride != 1, we verify the algorithm against the naivest possible
// implementation
let mut align = 1;
let mut x = false;
while align < 1024 {
for ptr in 1usize..4 * align {
unsafe {
x |= test_weird_stride::<A3>(ptr as *const A3, align);
x |= test_weird_stride::<A4>(ptr as *const A4, align);
x |= test_weird_stride::<A5>(ptr as *const A5, align);
x |= test_weird_stride::<A6>(ptr as *const A6, align);
x |= test_weird_stride::<A7>(ptr as *const A7, align);
x |= test_weird_stride::<A8>(ptr as *const A8, align);
x |= test_weird_stride::<A9>(ptr as *const A9, align);
x |= test_weird_stride::<A10>(ptr as *const A10, align);
}
}
align = (align + 1).next_power_of_two();
}
assert!(!x);
}