[llvm lib] Fix endian bug in #189098 (#189778)

The bug was added in #189098. Both functions that I added/changed
assumed little-endian host memory layout when reading/writing
non-power-of-two byte sizes (3, 5, 6, 7). On big-endian hosts (SPARC,
s390x), memcpy copies bytes into the MSB end of a uint64_t, leaving the
value in the wrong bit position. Fix by offsetting the memcpy/write
pointer to always target the LSB bytes.
This commit is contained in:
Roy Shi 2026-04-01 08:59:02 -07:00 committed by GitHub
parent 6f0e961cc2
commit 046e23fa4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 12 additions and 15 deletions

View File

@ -55,15 +55,13 @@ void FileWriter::writeUnsigned(uint64_t Value, size_t ByteSize) {
assert((ByteSize == 8 || (Value & (uint64_t)-1 << (8 * ByteSize)) == 0) &&
"potential data loss: higher bits are non-zero");
// Swap and shift bytes if endianness doesn't match.
if (ByteOrder != llvm::endianness::native) {
// Say ByteSize is 3.
// high low
// Input bytes: 00 00 00 00 00 AA BB CC
// Swapped bytes: CC BB AA 00 00 00 00 00
// Shifted bytes: 00 00 00 00 00 CC BB AA
if (ByteOrder != llvm::endianness::native)
Value = sys::getSwappedBytes(Value) >> (8 * (8 - ByteSize));
}
OS.write(reinterpret_cast<const char *>(&Value), ByteSize);
// Write from the least significant bytes of Value regardless of host
// endianness.
OS.write(reinterpret_cast<const char *>(&Value) +
(sys::IsLittleEndianHost ? 0 : 8 - ByteSize),
ByteSize);
}
void FileWriter::fixup32(uint32_t U, uint64_t Offset) {

View File

@ -144,16 +144,15 @@ uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,
uint64_t offset = *offset_ptr;
if (!prepareRead(offset, byte_size, Err))
return val;
std::memcpy(&val, &Data.data()[offset], byte_size);
// Copy into the least significant bytes of val regardless of host
// endianness.
std::memcpy(reinterpret_cast<char *>(&val) +
(sys::IsLittleEndianHost ? 0 : 8 - byte_size),
&Data.data()[offset], byte_size);
// Swap the least significant bytes of val if endianness doesn't match.
if (sys::IsLittleEndianHost != IsLittleEndian)
// Say byte_size is 3.
// high low
// Read bytes: 00 00 00 00 00 AA BB CC
// Swapped bytes: CC BB AA 00 00 00 00 00
// Shifted bytes: 00 00 00 00 00 CC BB AA
val = sys::getSwappedBytes(val) >> (8 * (8 - byte_size));
// Advance the offset
*offset_ptr += byte_size;
return val;
}