about summary refs log tree commit diff
diff options
context:
space:
mode:
authorKevin Ballard <kevin@sb.org>2015-05-11 12:37:31 -0700
committerKevin Ballard <kevin@sb.org>2015-05-11 12:37:31 -0700
commitf2614f5858fed10e180102def32c60f180e46496 (patch)
tree88bb940d491cdea2b0a2eb0bf27d2a334edd46f9
parente1e34e9275918679336210874f8dd770323daa81 (diff)
downloadrust-f2614f5858fed10e180102def32c60f180e46496.tar.gz
rust-f2614f5858fed10e180102def32c60f180e46496.zip
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.
-rw-r--r--src/libcore/slice.rs38
-rw-r--r--src/test/run-pass/slice-of-zero-size-elements.rs32
2 files changed, 48 insertions, 22 deletions
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index 3abba314558..9db1ceddf0d 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -728,29 +728,29 @@ macro_rules! iterator {
 }
 
 macro_rules! make_slice {
-    ($t: ty => $result: ty: $start: expr, $end: expr) => {{
-        let diff = ($end as usize).wrapping_sub($start as usize);
-        let len = if mem::size_of::<T>() == 0 {
-            diff
+    ($start: expr, $end: expr) => {{
+        let start = $start;
+        let diff = ($end as usize).wrapping_sub(start as usize);
+        if size_from_ptr(start) == 0 {
+            // use a non-null pointer value
+            unsafe { from_raw_parts(1 as *const _, diff) }
         } else {
-            diff / mem::size_of::<$t>()
-        };
-        unsafe {
-            from_raw_parts($start, len)
+            let len = diff / size_from_ptr(start);
+            unsafe { from_raw_parts(start, len) }
         }
     }}
 }
 
 macro_rules! make_mut_slice {
-    ($t: ty => $result: ty: $start: expr, $end: expr) => {{
-        let diff = ($end as usize).wrapping_sub($start as usize);
-        let len = if mem::size_of::<T>() == 0 {
-            diff
+    ($start: expr, $end: expr) => {{
+        let start = $start;
+        let diff = ($end as usize).wrapping_sub(start as usize);
+        if size_from_ptr(start) == 0 {
+            // use a non-null pointer value
+            unsafe { from_raw_parts_mut(1 as *mut _, diff) }
         } else {
-            diff / mem::size_of::<$t>()
-        };
-        unsafe {
-            from_raw_parts_mut($start, len)
+            let len = diff / size_from_ptr(start);
+            unsafe { from_raw_parts_mut(start, len) }
         }
     }}
 }
@@ -773,7 +773,7 @@ impl<'a, T> Iter<'a, T> {
     /// iterator can continue to be used while this exists.
     #[unstable(feature = "core")]
     pub fn as_slice(&self) -> &'a [T] {
-        make_slice!(T => &'a [T]: self.ptr, self.end)
+        make_slice!(self.ptr, self.end)
     }
 
     // Helper function for Iter::nth
@@ -841,12 +841,12 @@ impl<'a, T> IterMut<'a, T> {
     /// restricted lifetimes that do not consume the iterator.
     #[unstable(feature = "core")]
     pub fn into_slice(self) -> &'a mut [T] {
-        make_mut_slice!(T => &'a mut [T]: self.ptr, self.end)
+        make_mut_slice!(self.ptr, self.end)
     }
 
     // Helper function for IterMut::nth
     fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
-        match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) {
+        match make_mut_slice!(self.ptr, self.end).get_mut(n) {
             Some(elem_ref) => unsafe {
                 self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1));
                 Some(slice_ref!(elem_ref))
diff --git a/src/test/run-pass/slice-of-zero-size-elements.rs b/src/test/run-pass/slice-of-zero-size-elements.rs
index 98b668031a8..6fe510586c7 100644
--- a/src/test/run-pass/slice-of-zero-size-elements.rs
+++ b/src/test/run-pass/slice-of-zero-size-elements.rs
@@ -10,8 +10,26 @@
 
 // compile-flags: -C debug-assertions
 
+#![feature(core)]
+
 use std::slice;
 
+fn foo<T>(v: &[T]) -> Option<&[T]> {
+    let mut it = v.iter();
+    for _ in 0..5 {
+        let _ = it.next();
+    }
+    Some(it.as_slice())
+}
+
+fn foo_mut<T>(v: &mut [T]) -> Option<&mut [T]> {
+    let mut it = v.iter_mut();
+    for _ in 0..5 {
+        let _ = it.next();
+    }
+    Some(it.into_slice())
+}
+
 pub fn main() {
     // In a slice of zero-size elements the pointer is meaningless.
     // Ensure iteration still works even if the pointer is at the end of the address space.
@@ -24,11 +42,19 @@ pub fn main() {
     assert!(it.nth(5).is_some());
     assert_eq!(it.count(), 4);
 
+    // Converting Iter to a slice should never have a null pointer
+    assert!(foo(slice).is_some());
+
+    // Test mutable iterators as well
     let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) };
     assert_eq!(slice.len(), 10);
     assert_eq!(slice.iter_mut().count(), 10);
 
-    let mut it = slice.iter_mut();
-    assert!(it.nth(5).is_some());
-    assert_eq!(it.count(), 4);
+    {
+        let mut it = slice.iter_mut();
+        assert!(it.nth(5).is_some());
+        assert_eq!(it.count(), 4);
+    }
+
+    assert!(foo_mut(slice).is_some())
 }