about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2020-02-29 13:39:47 +0100
committerRalf Jung <post@ralfj.de>2020-02-29 14:53:20 +0100
commitc34451ffb78e0a0851c7aa97897a1621beed8c82 (patch)
treed452f73ec7ee91a4a72abe8df6790f7f326a676b
parent04e7f96dd89b1f0ad615dff1c85d11d4c4c64cb4 (diff)
downloadrust-c34451ffb78e0a0851c7aa97897a1621beed8c82.tar.gz
rust-c34451ffb78e0a0851c7aa97897a1621beed8c82.zip
fix aliasing violation in align_to_mut
-rw-r--r--src/libcore/slice/mod.rs4
-rw-r--r--src/libcore/tests/slice.rs12
2 files changed, 15 insertions, 1 deletions
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 7c65f595790..bb732b5fc3f 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -2571,11 +2571,13 @@ impl<T> [T] {
             let (left, rest) = self.split_at_mut(offset);
             // now `rest` is definitely aligned, so `from_raw_parts_mut` below is okay
             let (us_len, ts_len) = rest.align_to_offsets::<U>();
+            let rest_len = rest.len();
             let mut_ptr = rest.as_mut_ptr();
+            // We can't use `rest` again after this, that would invalidate its alias `mut_ptr`!
             (
                 left,
                 from_raw_parts_mut(mut_ptr as *mut U, us_len),
-                from_raw_parts_mut(mut_ptr.add(rest.len() - ts_len), ts_len),
+                from_raw_parts_mut(mut_ptr.add(rest_len - ts_len), ts_len),
             )
         }
     }
diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index cc274b4aecf..dbab433e33f 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -1571,6 +1571,18 @@ fn test_align_to_empty_mid() {
 }
 
 #[test]
+fn test_align_to_mut_aliasing() {
+    let mut val = [1u8, 2, 3, 4, 5];
+    // `align_to_mut` used to create `mid` in a way that there was some intermediate
+    // incorrect aliasing, invalidating the resulting `mid` slice.
+    let (begin, mid, end) = unsafe { val.align_to_mut::<[u8; 2]>() };
+    assert!(begin.len() == 0);
+    assert!(end.len() == 1);
+    mid[0] = mid[1];
+    assert_eq!(val, [3, 4, 3, 4, 5])
+}
+
+#[test]
 fn test_slice_partition_dedup_by() {
     let mut slice: [i32; 9] = [1, -1, 2, 3, 1, -5, 5, -2, 2];