Skip to content

Commit f2614f5

Browse files
committed
Avoid returning a slice with a null pointer from Iter.as_slice()
core::slice::Iter.ptr can be null when iterating a slice of zero-sized elements, but the pointer value used for the slice itself cannot. Handle this case by always returning a dummy pointer for slices of zero-sized elements.
1 parent e1e34e9 commit f2614f5

File tree

2 files changed

+48
-22
lines changed

2 files changed

+48
-22
lines changed

src/libcore/slice.rs

+19-19
Original file line numberDiff line numberDiff line change
@@ -728,29 +728,29 @@ macro_rules! iterator {
728728
}
729729

730730
macro_rules! make_slice {
731-
($t: ty => $result: ty: $start: expr, $end: expr) => {{
732-
let diff = ($end as usize).wrapping_sub($start as usize);
733-
let len = if mem::size_of::<T>() == 0 {
734-
diff
731+
($start: expr, $end: expr) => {{
732+
let start = $start;
733+
let diff = ($end as usize).wrapping_sub(start as usize);
734+
if size_from_ptr(start) == 0 {
735+
// use a non-null pointer value
736+
unsafe { from_raw_parts(1 as *const _, diff) }
735737
} else {
736-
diff / mem::size_of::<$t>()
737-
};
738-
unsafe {
739-
from_raw_parts($start, len)
738+
let len = diff / size_from_ptr(start);
739+
unsafe { from_raw_parts(start, len) }
740740
}
741741
}}
742742
}
743743

744744
macro_rules! make_mut_slice {
745-
($t: ty => $result: ty: $start: expr, $end: expr) => {{
746-
let diff = ($end as usize).wrapping_sub($start as usize);
747-
let len = if mem::size_of::<T>() == 0 {
748-
diff
745+
($start: expr, $end: expr) => {{
746+
let start = $start;
747+
let diff = ($end as usize).wrapping_sub(start as usize);
748+
if size_from_ptr(start) == 0 {
749+
// use a non-null pointer value
750+
unsafe { from_raw_parts_mut(1 as *mut _, diff) }
749751
} else {
750-
diff / mem::size_of::<$t>()
751-
};
752-
unsafe {
753-
from_raw_parts_mut($start, len)
752+
let len = diff / size_from_ptr(start);
753+
unsafe { from_raw_parts_mut(start, len) }
754754
}
755755
}}
756756
}
@@ -773,7 +773,7 @@ impl<'a, T> Iter<'a, T> {
773773
/// iterator can continue to be used while this exists.
774774
#[unstable(feature = "core")]
775775
pub fn as_slice(&self) -> &'a [T] {
776-
make_slice!(T => &'a [T]: self.ptr, self.end)
776+
make_slice!(self.ptr, self.end)
777777
}
778778

779779
// Helper function for Iter::nth
@@ -841,12 +841,12 @@ impl<'a, T> IterMut<'a, T> {
841841
/// restricted lifetimes that do not consume the iterator.
842842
#[unstable(feature = "core")]
843843
pub fn into_slice(self) -> &'a mut [T] {
844-
make_mut_slice!(T => &'a mut [T]: self.ptr, self.end)
844+
make_mut_slice!(self.ptr, self.end)
845845
}
846846

847847
// Helper function for IterMut::nth
848848
fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
849-
match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) {
849+
match make_mut_slice!(self.ptr, self.end).get_mut(n) {
850850
Some(elem_ref) => unsafe {
851851
self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1));
852852
Some(slice_ref!(elem_ref))

src/test/run-pass/slice-of-zero-size-elements.rs

+29-3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,26 @@
1010

1111
// compile-flags: -C debug-assertions
1212

13+
#![feature(core)]
14+
1315
use std::slice;
1416

17+
fn foo<T>(v: &[T]) -> Option<&[T]> {
18+
let mut it = v.iter();
19+
for _ in 0..5 {
20+
let _ = it.next();
21+
}
22+
Some(it.as_slice())
23+
}
24+
25+
fn foo_mut<T>(v: &mut [T]) -> Option<&mut [T]> {
26+
let mut it = v.iter_mut();
27+
for _ in 0..5 {
28+
let _ = it.next();
29+
}
30+
Some(it.into_slice())
31+
}
32+
1533
pub fn main() {
1634
// In a slice of zero-size elements the pointer is meaningless.
1735
// Ensure iteration still works even if the pointer is at the end of the address space.
@@ -24,11 +42,19 @@ pub fn main() {
2442
assert!(it.nth(5).is_some());
2543
assert_eq!(it.count(), 4);
2644

45+
// Converting Iter to a slice should never have a null pointer
46+
assert!(foo(slice).is_some());
47+
48+
// Test mutable iterators as well
2749
let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) };
2850
assert_eq!(slice.len(), 10);
2951
assert_eq!(slice.iter_mut().count(), 10);
3052

31-
let mut it = slice.iter_mut();
32-
assert!(it.nth(5).is_some());
33-
assert_eq!(it.count(), 4);
53+
{
54+
let mut it = slice.iter_mut();
55+
assert!(it.nth(5).is_some());
56+
assert_eq!(it.count(), 4);
57+
}
58+
59+
assert!(foo_mut(slice).is_some())
3460
}

0 commit comments

Comments
 (0)