]> git.lizzy.rs Git - rust.git/commitdiff
Avoid latent (harmless) overflow in core::slice.
authorFelix S. Klock II <pnkfelix@pnkfx.org>
Thu, 30 Apr 2015 23:00:48 +0000 (01:00 +0200)
committerFelix S. Klock II <pnkfelix@pnkfx.org>
Mon, 4 May 2015 07:57:42 +0000 (09:57 +0200)
This overflow does not cause any problems; it just causes errors to be
signalled when compiling with `-C debug-assertions`.

Fix #24997

src/libcore/slice.rs

index 38e66c5a3d6a2460e4e474a41f7e0c78a0ffb287..d99ea607e5db3755530df747140964dba0cd12b0 100644 (file)
@@ -631,8 +631,14 @@ fn size_from_ptr<T>(_: *const T) -> usize {
 }
 
 
-// Use macro to be generic over const/mut
-macro_rules! slice_offset {
+// Use macros to be generic over const/mut
+//
+// They require non-negative `$by` because otherwise the expression
+// `(ptr as usize + $by)` would interpret `-1` as `usize::MAX` (and
+// thus trigger a panic when overflow checks are on).
+
+// Use this to do `$ptr + $by`, where `$by` is non-negative.
+macro_rules! slice_add_offset {
     ($ptr:expr, $by:expr) => {{
         let ptr = $ptr;
         if size_from_ptr(ptr) == 0 {
@@ -643,6 +649,18 @@ macro_rules! slice_offset {
     }};
 }
 
+// Use this to do `$ptr - $by`, where `$by` is non-negative.
+macro_rules! slice_sub_offset {
+    ($ptr:expr, $by:expr) => {{
+        let ptr = $ptr;
+        if size_from_ptr(ptr) == 0 {
+            transmute(ptr as usize - $by)
+        } else {
+            ptr.offset(-$by)
+        }
+    }};
+}
+
 macro_rules! slice_ref {
     ($ptr:expr) => {{
         let ptr = $ptr;
@@ -672,7 +690,7 @@ fn next(&mut self) -> Option<$elem> {
                         None
                     } else {
                         let old = self.ptr;
-                        self.ptr = slice_offset!(self.ptr, 1);
+                        self.ptr = slice_add_offset!(self.ptr, 1);
                         Some(slice_ref!(old))
                     }
                 }
@@ -714,7 +732,7 @@ fn next_back(&mut self) -> Option<$elem> {
                     if self.end == self.ptr {
                         None
                     } else {
-                        self.end = slice_offset!(self.end, -1);
+                        self.end = slice_sub_offset!(self.end, 1);
                         Some(slice_ref!(self.end))
                     }
                 }
@@ -816,7 +834,7 @@ pub fn as_slice(&self) -> &'a [T] {
     fn iter_nth(&mut self, n: usize) -> Option<&'a T> {
         match self.as_slice().get(n) {
             Some(elem_ref) => unsafe {
-                self.ptr = slice_offset!(elem_ref as *const _, 1);
+                self.ptr = slice_add_offset!(elem_ref as *const _, 1);
                 Some(slice_ref!(elem_ref))
             },
             None => {
@@ -959,7 +977,7 @@ pub fn into_slice(self) -> &'a mut [T] {
     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) {
             Some(elem_ref) => unsafe {
-                self.ptr = slice_offset!(elem_ref as *mut _, 1);
+                self.ptr = slice_add_offset!(elem_ref as *mut _, 1);
                 Some(slice_ref!(elem_ref))
             },
             None => {