On a target whose ABI gives some scalar types a smaller alignment than their
size, FlatBufferBuilder can insert padding between a string's length prefix
and its payload. The result does not match the wire format and cannot be read
back — not even through FlatBuffers' own String accessor on the machine that
wrote it.
The default m68k Linux ABI is such a target: GCC gives uint32_t 2-byte
alignment even though it occupies 4 bytes. Thus __alignof__(uint32_t) is 2
while sizeof(uint32_t) is 4.
Reproducer
#include <flatbuffers/flatbuffers.h>
#include <cstdint>
#include <cstdio>
#include <cstring>
int main()
{
const char *kText = "m68k";
const size_t kLen = strlen(kText);
printf("sizeof(uoffset_t)=%zu AlignOf<uoffset_t>()=%zu __alignof__=%zu\n",
sizeof(flatbuffers::uoffset_t),
flatbuffers::AlignOf<flatbuffers::uoffset_t>(),
(size_t)__alignof__(flatbuffers::uoffset_t));
flatbuffers::FlatBufferBuilder fbb;
auto off = fbb.CreateString(kText, kLen);
const flatbuffers::String *string =
flatbuffers::GetTemporaryPointer(fbb, off);
const uint8_t *str = reinterpret_cast<const uint8_t *>(string);
const uint32_t len = string->size();
const char *data = string->c_str();
printf("raw bytes at the string offset:");
for (size_t i = 0; i < sizeof(uint32_t) + kLen + 2; i++)
printf(" %02x", str[i]);
printf("\n");
printf("length prefix = %lu (expected %zu)\n",
static_cast<unsigned long>(len), kLen);
printf("payload = \"%.*s\" (expected \"%s\")\n", (int)len, data, kText);
const bool ok = len == kLen && memcmp(data, kText, kLen) == 0;
printf("%s\n", ok ? "PASS" : "FAIL: padding between length prefix and payload");
return ok ? 0 : 1;
}
Build and run:
g++ -std=c++17 -I include repro.cc -o repro && ./repro
m68k-linux-gnu-g++ -std=c++17 -I include -static repro.cc -o repro-m68k
qemu-m68k ./repro-m68k # or run it on any m68k machine
Actual vs expected
x86-64 (correct):
sizeof(uoffset_t)=4 AlignOf<uoffset_t>()=4 __alignof__=4
raw bytes at the string offset: 04 00 00 00 6d 36 38 6b 00 00
length prefix = 4 (expected 4)
payload = "m68k" (expected "m68k")
PASS
m68k (broken):
sizeof(uoffset_t)=4 AlignOf<uoffset_t>()=2 __alignof__=2
raw bytes at the string offset: 04 00 00 00 00 00 6d 36 38 6b
length prefix = 4 (expected 4)
payload = "" (expected "m68k")
FAIL: padding between length prefix and payload
Note the two extra 00 bytes between the length prefix and 6d 36 38 6b.
On a target whose ABI gives some scalar types a smaller alignment than their
size,
FlatBufferBuildercan insert padding between a string's length prefixand its payload. The result does not match the wire format and cannot be read
back — not even through FlatBuffers' own
Stringaccessor on the machine thatwrote it.
The default m68k Linux ABI is such a target: GCC gives
uint32_t2-bytealignment even though it occupies 4 bytes. Thus
__alignof__(uint32_t)is 2while
sizeof(uint32_t)is 4.Reproducer
Build and run:
Actual vs expected
x86-64 (correct):
m68k (broken):
Note the two extra
00bytes between the length prefix and6d 36 38 6b.