Skip to content

Commit 46d1ee7

Browse files
committed
auto merge of rust-lang#16191 : DaGenix/rust/fix-aligned-access, r=alexcrichton
When I originally wrote the read_u32v_be() and write_u32_be() functions, I didn't consider memory alignment requirements of various architectures. Unfortunately, the current implementations may result in unaligned reads and writes. This doesn't impact x86 / x86_64, but it can cause a compiler crash on ARM. This pull requests rewrites those functions to make sure that all memory access is always correctly aligned. This fix is a little bit academic - due to the way that LLVM aligns the structures that are passed as arguments to these functions, I believe that the end result is that all memory access happens to be aligned anyway. However, there is nothing in that code that actually enforces that, at least not explicitly. The new implementations are definitely slower than the existing ones. However, I don't believe that these functions are all that significant when looking at the overall performance of the compiler. I think getting rid of some unsafe code and removing a potential portability landmine justifies a very slight decrease in raw performance.
2 parents 12306da + fd69365 commit 46d1ee7

File tree

1 file changed

+17
-15
lines changed

1 file changed

+17
-15
lines changed

src/librustc_back/sha2.rs

+17-15
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,28 @@ use serialize::hex::ToHex;
2222
/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian
2323
/// format.
2424
fn write_u32_be(dst: &mut[u8], input: u32) {
25-
use std::mem::to_be32;
26-
assert!(dst.len() == 4);
27-
unsafe {
28-
let x = dst.unsafe_mut_ref(0) as *mut _ as *mut u32;
29-
*x = to_be32(input);
30-
}
25+
dst[0] = (input >> 24) as u8;
26+
dst[1] = (input >> 16) as u8;
27+
dst[2] = (input >> 8) as u8;
28+
dst[3] = input as u8;
29+
}
30+
31+
/// Read the value of a vector of bytes as a u32 value in big-endian format.
32+
fn read_u32_be(input: &[u8]) -> u32 {
33+
return
34+
(input[0] as u32) << 24 |
35+
(input[1] as u32) << 16 |
36+
(input[2] as u32) << 8 |
37+
(input[3] as u32);
3138
}
3239

3340
/// Read a vector of bytes into a vector of u32s. The values are read in big-endian format.
3441
fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
35-
use std::mem::to_be32;
3642
assert!(dst.len() * 4 == input.len());
37-
unsafe {
38-
let mut x = dst.unsafe_mut_ref(0) as *mut _ as *mut u32;
39-
let mut y = input.unsafe_ref(0) as *const _ as *const u32;
40-
for _ in range(0, dst.len()) {
41-
*x = to_be32(*y);
42-
x = x.offset(1);
43-
y = y.offset(1);
44-
}
43+
let mut pos = 0u;
44+
for chunk in input.chunks(4) {
45+
dst[pos] = read_u32_be(chunk);
46+
pos += 1;
4547
}
4648
}
4749

0 commit comments

Comments
 (0)