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
committerAlex Crichton <alex@alexcrichton.com>2016-09-12 16:58:25 -0700
commit3ca48fe73e4ce50f36839fb6e4486dcb3fc6c203 (patch)
treed1cc2b44913e455183fd3028ce258be8aa5918b3
parent2e1b8d37e973bfd7be704d58b43896d27e8048be (diff)
downloadrust-3ca48fe73e4ce50f36839fb6e4486dcb3fc6c203.tar.gz
rust-3ca48fe73e4ce50f36839fb6e4486dcb3fc6c203.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..]));
+        }
+    }
 }