mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-30 04:24:26 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			416 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			416 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| 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 doesn’t 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]
 | ||
| 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]
 | ||
| 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]
 | ||
| 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;
 | ||
|     // Miri is too slow
 | ||
|     let limit = if cfg!(miri) { 32 } else { 1024 };
 | ||
|     while align < limit {
 | ||
|         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);
 | ||
| }
 | ||
| 
 | ||
| #[test]
 | ||
| fn offset_from() {
 | ||
|     let mut a = [0; 5];
 | ||
|     let ptr1: *mut i32 = &mut a[1];
 | ||
|     let ptr2: *mut i32 = &mut a[3];
 | ||
|     unsafe {
 | ||
|         assert_eq!(ptr2.offset_from(ptr1), 2);
 | ||
|         assert_eq!(ptr1.offset_from(ptr2), -2);
 | ||
|         assert_eq!(ptr1.offset(2), ptr2);
 | ||
|         assert_eq!(ptr2.offset(-2), ptr1);
 | ||
|     }
 | ||
| }
 | 
