]> git.lizzy.rs Git - rust.git/commitdiff
memrchr: Correct aligned offset computation
authorUlrik Sverdrup <bluss@users.noreply.github.com>
Wed, 24 Aug 2016 16:57:45 +0000 (18:57 +0200)
committerUlrik Sverdrup <bluss@users.noreply.github.com>
Wed, 24 Aug 2016 17:05:21 +0000 (19:05 +0200)
The memrchr fallback did not compute the offset correctly. It was
intentioned to land on usize-aligned addresses but did not.
This was suspected to resulted in a crash on ARMv7 platform!

This bug affected non-linux platforms.

I think like this, if we have a slice with pointer `ptr` and length
`len`, we want to find the last usize-aligned offset in the slice.
The correct computation should be:

For example if ptr = 1 and len = 6, and size_of::<usize>() is 4:

[ x x x x x x ]
  1 2 3 4 5 6
        ^-- last aligned address at offset 3 from the start.

The last aligned address is ptr + len - (ptr + len) % usize_size.

Compute offset from the start as:

offset = len - (ptr + len) % usize_size = 6 - (1 + 6) % 4 = 6 - 3 = 3.

I believe the function's return value was always correct previously, if
the platform supported unaligned addresses.

src/libstd/memchr.rs

index a408b4378e19e6b14cdb0f68478adf628f527dc0..89b77a7d6614e8a6d72d7638ef06a9938699af0b 100644 (file)
@@ -209,7 +209,7 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
         let end_align = (ptr as usize + len) & (usize_bytes - 1);
         let mut offset;
         if end_align > 0 {
-            offset = len - cmp::min(usize_bytes - end_align, len);
+            offset = len - cmp::min(end_align, len);
             if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
                 return Some(offset + index);
             }
@@ -309,6 +309,17 @@ fn no_match_empty_reversed() {
     fn no_match_reversed() {
         assert_eq!(None, memrchr(b'a', b"xyz"));
     }
+
+    #[test]
+    fn each_alignment_reversed() {
+        let mut data = [1u8; 64];
+        let needle = 2;
+        let pos = 40;
+        data[pos] = needle;
+        for start in 0..16 {
+            assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
+        }
+    }
 }
 
 #[cfg(test)]
@@ -385,4 +396,15 @@ fn no_match_empty_reversed() {
     fn no_match_reversed() {
         assert_eq!(None, memrchr(b'a', b"xyz"));
     }
+
+    #[test]
+    fn each_alignment() {
+        let mut data = [1u8; 64];
+        let needle = 2;
+        let pos = 40;
+        data[pos] = needle;
+        for start in 0..16 {
+            assert_eq!(Some(pos - start), memchr(needle, &data[start..]));
+        }
+    }
 }