filamat: fix ubsan failure (#8461)

Enabling UBSan shows the following error:

SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior filamat/src/eiff/Flattener.h:102:17 in
filamat/src/eiff/Flattener.h:102:17: runtime error: applying non-zero offset 8 to null pointer

We reference a placeholder byte on the heap when in DryRunner mode
to workaround this issue.
This commit is contained in:
Powei Feng
2025-02-26 19:55:30 -08:00
committed by GitHub
parent e414b99c09
commit dc7eee0896

View File

@@ -34,44 +34,54 @@
using namespace utils;
namespace {
constexpr uint8_t FAKE_DRY_RUNNER_START_ADDR = 0x1;
} // anonymous
namespace filamat {
class Flattener {
public:
explicit Flattener(uint8_t* dst) : mCursor(dst), mStart(dst){}
// DryRunner is used to compute the size of the flattened output but not actually carry out
// flattening. If we set mStart = nullptr and mEnd=nullptr, we would hit an error about
// offsetting on null when ubsan is enabled. Instead we point mStart to a fake address, and
// mCursor is offset from that.
static Flattener& getDryRunner() {
static Flattener dryRunner = Flattener(nullptr);
dryRunner.mStart = nullptr;
dryRunner.mCursor = nullptr;
dryRunner.mStart = (uint8_t*) FAKE_DRY_RUNNER_START_ADDR;
dryRunner.mCursor = (uint8_t*) FAKE_DRY_RUNNER_START_ADDR;
dryRunner.mOffsetPlaceholders.clear();
dryRunner.mSizePlaceholders.clear();
dryRunner.mValuePlaceholders.clear();
return dryRunner;
}
bool isDryRunner() { return mStart == nullptr;}
bool isDryRunner() {
return mStart == (uint8_t*) FAKE_DRY_RUNNER_START_ADDR;
}
size_t getBytesWritten() {
return mCursor - mStart;
}
void writeBool(bool b) {
if (mStart != nullptr) {
if (!isDryRunner()) {
mCursor[0] = static_cast<uint8_t>(b);
}
mCursor += 1;
}
void writeUint8(uint8_t i) {
if (mStart != nullptr) {
if (!isDryRunner()) {
mCursor[0] = i;
}
mCursor += 1;
}
void writeUint16(uint16_t i) {
if (mStart != nullptr) {
if (!isDryRunner()) {
mCursor[0] = static_cast<uint8_t>( i & 0xff);
mCursor[1] = static_cast<uint8_t>((i >> 8) & 0xff);
}
@@ -79,7 +89,7 @@ public:
}
void writeUint32(uint32_t i) {
if (mStart != nullptr) {
if (!isDryRunner()) {
mCursor[0] = static_cast<uint8_t>( i & 0xff);
mCursor[1] = static_cast<uint8_t>((i >> 8) & 0xff);
mCursor[2] = static_cast<uint8_t>((i >> 16) & 0xff);
@@ -89,7 +99,7 @@ public:
}
void writeUint64(uint64_t i) {
if (mStart != nullptr) {
if (!isDryRunner()) {
mCursor[0] = static_cast<uint8_t>( i & 0xff);
mCursor[1] = static_cast<uint8_t>((i >> 8) & 0xff);
mCursor[2] = static_cast<uint8_t>((i >> 16) & 0xff);
@@ -104,7 +114,7 @@ public:
void writeString(const char* str) {
size_t const len = strlen(str);
if (mStart != nullptr) {
if (!isDryRunner()) {
strcpy(reinterpret_cast<char*>(mCursor), str);
}
mCursor += len + 1;
@@ -112,7 +122,7 @@ public:
void writeString(std::string_view str) {
size_t const len = str.length();
if (mStart != nullptr) {
if (!isDryRunner()) {
memcpy(reinterpret_cast<char*>(mCursor), str.data(), len);
mCursor[len] = 0;
}
@@ -121,14 +131,14 @@ public:
void writeBlob(const char* blob, size_t nbytes) {
writeUint64(nbytes);
if (mStart != nullptr) {
if (!isDryRunner()) {
memcpy(reinterpret_cast<char*>(mCursor), blob, nbytes);
}
mCursor += nbytes;
}
void writeRaw(const char* raw, size_t nbytes) {
if (mStart != nullptr) {
if (!isDryRunner()) {
memcpy(reinterpret_cast<char*>(mCursor), raw, nbytes);
}
mCursor += nbytes;
@@ -136,7 +146,7 @@ public:
void writeSizePlaceholder() {
mSizePlaceholders.push_back(mCursor);
if (mStart != nullptr) {
if (!isDryRunner()) {
mCursor[0] = 0;
mCursor[1] = 0;
mCursor[2] = 0;
@@ -164,7 +174,7 @@ public:
mSizePlaceholders.pop_back();
// -4 to account for the 4 bytes we are about to write.
uint32_t const size = static_cast<uint32_t>(mCursor - dst - 4);
if (mStart != nullptr) {
if (!isDryRunner()) {
dst[0] = static_cast<uint8_t>( size & 0xff);
dst[1] = static_cast<uint8_t>((size >> 8) & 0xff);
dst[2] = static_cast<uint8_t>((size >> 16) & 0xff);
@@ -175,7 +185,7 @@ public:
void writeOffsetplaceholder(size_t index) {
mOffsetPlaceholders.insert(std::pair<size_t, uint8_t*>(index, mCursor));
if (mStart != nullptr) {
if (!isDryRunner()) {
mCursor[0] = 0x0;
mCursor[1] = 0x0;
mCursor[2] = 0x0;
@@ -185,7 +195,7 @@ public:
}
void writeOffsets(uint32_t forIndex) {
if (mStart == nullptr) {
if (isDryRunner()) {
return;
}
@@ -209,7 +219,7 @@ public:
void writeValuePlaceholder() {
mValuePlaceholders.push_back(mCursor);
if (mStart != nullptr) {
if (!isDryRunner()) {
mCursor[0] = 0;
mCursor[1] = 0;
mCursor[2] = 0;
@@ -228,7 +238,7 @@ public:
uint8_t* dst = mValuePlaceholders.back();
mValuePlaceholders.pop_back();
if (mStart != nullptr) {
if (!isDryRunner()) {
dst[0] = static_cast<uint8_t>( v & 0xff);
dst[1] = static_cast<uint8_t>((v >> 8) & 0xff);
dst[2] = static_cast<uint8_t>((v >> 16) & 0xff);