Skip to content

Commit

Permalink
memrchr: Correct aligned offset computation
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bluss committed Aug 24, 2016
1 parent 4901896 commit d1ecee9
Showing 1 changed file with 23 additions and 1 deletion.
24 changes: 23 additions & 1 deletion src/libstd/memchr.rs
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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..]));
}
}
}

0 comments on commit d1ecee9

Please sign in to comment.