Description
commit 7bc1054 attempted to fix unaligned loads, but appears to have only resolved part of the problem and may have unintentionally left things a little broken on architectures with strict alignment requirements.
That commit changed bytes_to_words to return &[Unaligned<u32>]
, but made that type #[repr(packed)]
.
I'm currently working with a fellow colleague on a port of rust to another architecture and we hit this:
Thread 4 received signal SIGSEGV, Segmentation fault.
[Switching to Thread 2 (LWP 2)]
0xffffffff50037b34 in rustc_metadata::schema::LazySeq<rustc_metadata::index::Index>::lookup (self=0xffffffff7b861df0, bytes=..., def_index=...)
at /builds/rust.git/src/librustc_metadata/index.rs:73
73 let position = u32::from_le(words[index].get());
(gdb) print words
$37 = &[rustc_metadata::index::Unaligned<u32>] {data_ptr: 0xffffffff793ae6b6, length: 6908}
(gdb) print index
$38 = 5283
(gdb) print words[index]
$39 = rustc_metadata::index::Unaligned<u32> (4092795392)
A disassembly of the call site shows this:
(gdb) disassemble 0xffffffff50037b34-16,+32
Dump of assembler code from 0xffffffff50037b24 to 0xffffffff50037b44:
0xffffffff50037b24 <rustc_metadata::schema::LazySeq<rustc_metadata::index::Index>::lookup+864>: nop
0xffffffff50037b28 <rustc_metadata::schema::LazySeq<rustc_metadata::index::Index>::lookup+868>: ldx [ %fp + 0x627 ], %i0
0xffffffff50037b2c <rustc_metadata::schema::LazySeq<rustc_metadata::index::Index>::lookup+872>: ldx [ %fp + 0x537 ], %i1
0xffffffff50037b30 <rustc_metadata::schema::LazySeq<rustc_metadata::index::Index>::lookup+876>: sllx %i1, 2, %i2
=> 0xffffffff50037b34 <rustc_metadata::schema::LazySeq<rustc_metadata::index::Index>::lookup+880>: ld [ %i0 + %i2 ], %i0
0xffffffff50037b38 <rustc_metadata::schema::LazySeq<rustc_metadata::index::Index>::lookup+884>: st %i0, [ %fp + 0x6e7 ]
0xffffffff50037b3c <rustc_metadata::schema::LazySeq<rustc_metadata::index::Index>::lookup+888>: st %i0, [ %fp + 0x7d7 ]
0xffffffff50037b40 <rustc_metadata::schema::LazySeq<rustc_metadata::index::Index>::lookup+892>: call 0xffffffff50038054 <rustc_metadata::index::Unaligned<u32>::get<u32>>
(gdb) print/a $i0
$40 = 0xffffffff793ae6b6
(gdb) print/a $i2
$41 = 0x528c
(gdb) print/a ($i0+$i2)
$42 = 0xffffffff793b3942
(gdb) print/x *($i0+$i2)
$44 = 0xf3f31a00
Now, if I'm not mistaken it looks like it's trying to perform an ld
(aka lduw
; load unsigned word) and a word is 4 bytes, but the offset of the memory address it's trying to read from is byte-aligned, not word-aligned, due to the #[repr(packed)]
, which I believe is causing the fault since what seems like a valid value appears to be there.
I suspect this is another case of issue #27060, but while we're waiting for that to be fixed, should the packed directive be removed instead?
I plan to try that fix myself soon, but wanted confirmation that was a reasonable change before attempting it.