diff options
| author | Ulrik Sverdrup <bluss@users.noreply.github.com> | 2016-08-24 18:57:45 +0200 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2016-09-12 16:58:25 -0700 |
| commit | 3ca48fe73e4ce50f36839fb6e4486dcb3fc6c203 (patch) | |
| tree | d1cc2b44913e455183fd3028ce258be8aa5918b3 | |
| parent | 2e1b8d37e973bfd7be704d58b43896d27e8048be (diff) | |
| download | rust-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.rs | 24 |
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..])); + } + } } |
