about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrik Sverdrup <bluss@users.noreply.github.com>2016-08-24 18:57:45 +0200
committerUlrik Sverdrup <bluss@users.noreply.github.com>2016-08-24 19:05:21 +0200
commitd1ecee96bfb7fb52b67358302c524a8c0193dc23 (patch)
treecb8e0f2ac468455b045a8d712d416e36f79807aa
parent490189634b656dcca9e41e6b52093569c03bd4df (diff)
downloadrust-d1ecee96bfb7fb52b67358302c524a8c0193dc23.tar.gz
rust-d1ecee96bfb7fb52b67358302c524a8c0193dc23.zip
memrchr: Correct aligned offset computation
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.
-rw-r--r--src/libstd/memchr.rs24
1 files changed, 23 insertions, 1 deletions
diff --git a/src/libstd/memchr.rs b/src/libstd/memchr.rs
index a408b4378e1..89b77a7d661 100644
--- a/src/libstd/memchr.rs
+++ b/src/libstd/memchr.rs
@@ -209,7 +209,7 @@ mod fallback {
         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 @@ mod fallback {
     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 @@ mod tests {
     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..]));
+        }
+    }
 }