Skip to content

Commit d1ecee9

Browse files
committed
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.
1 parent 4901896 commit d1ecee9

File tree

1 file changed

+23
-1
lines changed

1 file changed

+23
-1
lines changed

Diff for: src/libstd/memchr.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ mod fallback {
209209
let end_align = (ptr as usize + len) & (usize_bytes - 1);
210210
let mut offset;
211211
if end_align > 0 {
212-
offset = len - cmp::min(usize_bytes - end_align, len);
212+
offset = len - cmp::min(end_align, len);
213213
if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
214214
return Some(offset + index);
215215
}
@@ -309,6 +309,17 @@ mod fallback {
309309
fn no_match_reversed() {
310310
assert_eq!(None, memrchr(b'a', b"xyz"));
311311
}
312+
313+
#[test]
314+
fn each_alignment_reversed() {
315+
let mut data = [1u8; 64];
316+
let needle = 2;
317+
let pos = 40;
318+
data[pos] = needle;
319+
for start in 0..16 {
320+
assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
321+
}
322+
}
312323
}
313324

314325
#[cfg(test)]
@@ -385,4 +396,15 @@ mod tests {
385396
fn no_match_reversed() {
386397
assert_eq!(None, memrchr(b'a', b"xyz"));
387398
}
399+
400+
#[test]
401+
fn each_alignment() {
402+
let mut data = [1u8; 64];
403+
let needle = 2;
404+
let pos = 40;
405+
data[pos] = needle;
406+
for start in 0..16 {
407+
assert_eq!(Some(pos - start), memchr(needle, &data[start..]));
408+
}
409+
}
388410
}

0 commit comments

Comments
 (0)