Skip to content

Commit 5cebe34

Browse files
committed
add some tests for ZST slices, and fix failures due to unaligned references
1 parent 77d8059 commit 5cebe34

File tree

2 files changed

+107
-36
lines changed

2 files changed

+107
-36
lines changed

src/libcore/slice/mod.rs

+38-36
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use option::Option;
4545
use option::Option::{None, Some};
4646
use result::Result;
4747
use result::Result::{Ok, Err};
48-
use ptr;
48+
use ptr::{self, NonNull};
4949
use mem;
5050
use marker::{Copy, Send, Sync, Sized, self};
5151
use iter_private::TrustedRandomAccess;
@@ -80,7 +80,7 @@ macro_rules! slice_offset {
8080
($ptr:expr, $by:expr) => {{
8181
let ptr = $ptr;
8282
if size_from_ptr(ptr) == 0 {
83-
(ptr as *mut i8).wrapping_offset($by) as _
83+
(ptr as *mut i8).wrapping_offset($by.wrapping_mul(align_from_ptr(ptr) as isize)) as _
8484
} else {
8585
ptr.offset($by)
8686
}
@@ -93,7 +93,7 @@ macro_rules! make_ref {
9393
let ptr = $ptr;
9494
if size_from_ptr(ptr) == 0 {
9595
// Use a non-null pointer value
96-
&*(1 as *mut _)
96+
&*(NonNull::dangling().as_ptr() as *const _)
9797
} else {
9898
&*ptr
9999
}
@@ -106,13 +106,39 @@ macro_rules! make_ref_mut {
106106
let ptr = $ptr;
107107
if size_from_ptr(ptr) == 0 {
108108
// Use a non-null pointer value
109-
&mut *(1 as *mut _)
109+
&mut *(NonNull::dangling().as_ptr())
110110
} else {
111111
&mut *ptr
112112
}
113113
}};
114114
}
115115

116+
macro_rules! make_slice {
117+
($start: expr, $end: expr) => {{
118+
let start = $start;
119+
let len = unsafe { ptrdistance($start, $end) };
120+
if size_from_ptr(start) == 0 {
121+
// use a non-null pointer value
122+
unsafe { from_raw_parts(NonNull::dangling().as_ptr() as *const _, len) }
123+
} else {
124+
unsafe { from_raw_parts(start, len) }
125+
}
126+
}}
127+
}
128+
129+
macro_rules! make_mut_slice {
130+
($start: expr, $end: expr) => {{
131+
let start = $start;
132+
let len = unsafe { ptrdistance($start, $end) };
133+
if size_from_ptr(start) == 0 {
134+
// use a non-null pointer value
135+
unsafe { from_raw_parts_mut(NonNull::dangling().as_ptr(), len) }
136+
} else {
137+
unsafe { from_raw_parts_mut(start, len) }
138+
}
139+
}}
140+
}
141+
116142
#[lang = "slice"]
117143
#[cfg(not(test))]
118144
impl<T> [T] {
@@ -581,7 +607,7 @@ impl<T> [T] {
581607
pub fn iter(&self) -> Iter<T> {
582608
unsafe {
583609
let p = if mem::size_of::<T>() == 0 {
584-
1 as *const _
610+
NonNull::dangling().as_ptr() as *const _
585611
} else {
586612
let p = self.as_ptr();
587613
assume(!p.is_null());
@@ -612,7 +638,7 @@ impl<T> [T] {
612638
pub fn iter_mut(&mut self) -> IterMut<T> {
613639
unsafe {
614640
let p = if mem::size_of::<T>() == 0 {
615-
1 as *mut _
641+
NonNull::dangling().as_ptr()
616642
} else {
617643
let p = self.as_mut_ptr();
618644
assume(!p.is_null());
@@ -2369,6 +2395,11 @@ fn size_from_ptr<T>(_: *const T) -> usize {
23692395
mem::size_of::<T>()
23702396
}
23712397

2398+
#[inline]
2399+
fn align_from_ptr<T>(_: *const T) -> usize {
2400+
mem::align_of::<T>()
2401+
}
2402+
23722403
// The shared definition of the `Iter` and `IterMut` iterators
23732404
macro_rules! iterator {
23742405
(struct $name:ident -> $ptr:ty, $elem:ty, $mkref:ident) => {
@@ -2547,34 +2578,6 @@ macro_rules! iterator {
25472578
}
25482579
}
25492580

2550-
macro_rules! make_slice {
2551-
($start: expr, $end: expr) => {{
2552-
let start = $start;
2553-
let diff = ($end as usize).wrapping_sub(start as usize);
2554-
if size_from_ptr(start) == 0 {
2555-
// use a non-null pointer value
2556-
unsafe { from_raw_parts(1 as *const _, diff) }
2557-
} else {
2558-
let len = diff / size_from_ptr(start);
2559-
unsafe { from_raw_parts(start, len) }
2560-
}
2561-
}}
2562-
}
2563-
2564-
macro_rules! make_mut_slice {
2565-
($start: expr, $end: expr) => {{
2566-
let start = $start;
2567-
let diff = ($end as usize).wrapping_sub(start as usize);
2568-
if size_from_ptr(start) == 0 {
2569-
// use a non-null pointer value
2570-
unsafe { from_raw_parts_mut(1 as *mut _, diff) }
2571-
} else {
2572-
let len = diff / size_from_ptr(start);
2573-
unsafe { from_raw_parts_mut(start, len) }
2574-
}
2575-
}}
2576-
}
2577-
25782581
/// Immutable slice iterator
25792582
///
25802583
/// This struct is created by the [`iter`] method on [slices].
@@ -2791,11 +2794,10 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {
27912794
}
27922795

27932796
// Return the number of elements of `T` from `start` to `end`.
2794-
// Return the arithmetic difference if `T` is zero size.
27952797
#[inline(always)]
27962798
unsafe fn ptrdistance<T>(start: *const T, end: *const T) -> usize {
27972799
if mem::size_of::<T>() == 0 {
2798-
(end as usize).wrapping_sub(start as usize)
2800+
(end as usize).wrapping_sub(start as usize) / mem::align_of::<T>()
27992801
} else {
28002802
end.offset_from(start) as usize
28012803
}

src/libcore/tests/slice.rs

+69
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,75 @@ fn test_windows_zip() {
376376
assert_eq!(res, [14, 18, 22, 26]);
377377
}
378378

379+
#[test]
380+
#[allow(const_err)]
381+
fn test_iter_consistency() {
382+
use std::fmt::Debug;
383+
use std::mem;
384+
385+
fn helper<T : Copy + Debug + PartialEq>(x : T) {
386+
let v : &[T] = &[x, x, x];
387+
let len = v.len();
388+
389+
// TODO: Once #42789 is resolved, also compare the locations with each other
390+
// and with slice patterns.
391+
392+
for i in 0..len {
393+
let nth = v.iter().nth(i).unwrap();
394+
assert!(nth as *const _ as usize % mem::align_of::<T>() == 0);
395+
assert_eq!(nth, &x);
396+
}
397+
assert_eq!(v.iter().nth(len), None, "nth(len) should return None");
398+
399+
let mut it = v.iter();
400+
for i in 0..len{
401+
let remaining = len - i;
402+
assert_eq!(it.size_hint(), (remaining, Some(remaining)));
403+
404+
let next = it.next().unwrap();
405+
assert!(next as *const _ as usize % mem::align_of::<T>() == 0);
406+
assert_eq!(next, &x);
407+
}
408+
assert_eq!(it.size_hint(), (0, Some(0)));
409+
assert_eq!(it.next(), None, "The final call to next() should return None");
410+
}
411+
412+
fn helper_mut<T : Copy + Debug + PartialEq>(mut x : T) {
413+
let v : &mut [T] = &mut [x, x, x];
414+
let len = v.len();
415+
416+
// TODO: Once #42789 is resolved, also compare the locations with each other
417+
// and with slice patterns.
418+
419+
for i in 0..len {
420+
let nth = v.iter_mut().nth(i).unwrap();
421+
assert!(nth as *mut _ as usize % mem::align_of::<T>() == 0);
422+
assert_eq!(nth, &mut x);
423+
}
424+
assert_eq!(v.iter().nth(len), None, "nth(len) should return None");
425+
426+
let mut it = v.iter_mut();
427+
for i in 0..len {
428+
let remaining = len - i;
429+
assert_eq!(it.size_hint(), (remaining, Some(remaining)));
430+
431+
let next = it.next().unwrap();
432+
assert!(next as *mut _ as usize % mem::align_of::<T>() == 0);
433+
assert_eq!(next, &mut x);
434+
}
435+
assert_eq!(it.size_hint(), (0, Some(0)));
436+
assert_eq!(it.next(), None, "The final call to next() should return None");
437+
}
438+
439+
// Make sure this works consistently for various types, including ZSTs.
440+
helper(0u32);
441+
helper(());
442+
helper([0u32; 0]); // ZST with alignment > 0
443+
helper_mut(0u32);
444+
helper_mut(());
445+
helper_mut([0u32; 0]); // ZST with alignment > 0
446+
}
447+
379448
// The current implementation of SliceIndex fails to handle methods
380449
// orthogonally from range types; therefore, it is worth testing
381450
// all of the indexing operations on each input.

0 commit comments

Comments
 (0)