From 52efe55d0425d963ee949be96e36d584a603a455 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Mon, 11 May 2015 00:55:21 -0700 Subject: Handle overflow properly in core::slice core::slice was originally written to tolerate overflow (notably, with slices of zero-sized elements), but it was never updated to use wrapping arithmetic when overflow traps were added. Also correctly handle the case of calling .nth() on an Iter with a zero-sized element type. The iterator was assuming that the pointer value of the returned reference was meaningful, but that's not true for zero-sized elements. Fixes #25016. --- src/test/run-pass/slice-of-zero-size-elements.rs | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/test/run-pass/slice-of-zero-size-elements.rs (limited to 'src/test') diff --git a/src/test/run-pass/slice-of-zero-size-elements.rs b/src/test/run-pass/slice-of-zero-size-elements.rs new file mode 100644 index 00000000000..98b668031a8 --- /dev/null +++ b/src/test/run-pass/slice-of-zero-size-elements.rs @@ -0,0 +1,34 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C debug-assertions + +use std::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. + let slice: &[()] = unsafe { slice::from_raw_parts(-5isize as *const (), 10) }; + assert_eq!(slice.len(), 10); + assert_eq!(slice.iter().count(), 10); + + // .nth() on the iterator should also behave correctly + let mut it = slice.iter(); + assert!(it.nth(5).is_some()); + assert_eq!(it.count(), 4); + + 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); +} -- cgit 1.4.1-3-g733a5 From f2614f5858fed10e180102def32c60f180e46496 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Mon, 11 May 2015 12:37:31 -0700 Subject: 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. --- src/libcore/slice.rs | 38 ++++++++++++------------ src/test/run-pass/slice-of-zero-size-elements.rs | 32 ++++++++++++++++++-- 2 files changed, 48 insertions(+), 22 deletions(-) (limited to 'src/test') 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::() == 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::() == 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(v: &[T]) -> Option<&[T]> { + let mut it = v.iter(); + for _ in 0..5 { + let _ = it.next(); + } + Some(it.as_slice()) +} + +fn foo_mut(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()) } -- cgit 1.4.1-3-g733a5