Compare commits

..
6 Commits
Author SHA1 Message Date
Artyom Palvelev 5eb190f000 rust: fix 64-bit scalar wire-format alignment on 32-bit targets in Push::alignment (#9465)
In the FlatBuffers binary wire format specification, every scalar field is
aligned to its own byte size (`1`, `2`, `4`, or `8` bytes), regardless of the
host CPU architecture. Both the `flatc` schema compiler (when computing table
`max_align` and struct field offsets) and the C++ `FlatBufferBuilder::Align` /
`PushElement` implementation align 64-bit scalars (`u64`, `i64`, `f64`) to 8
bytes on all architectures.

However, in the Rust `flatbuffers` crate (`rust/flatbuffers/src/push.rs`), the
`Push` trait provides a default implementation:

```rust
fn alignment() -> PushAlignment {
    PushAlignment::new(align_of::<Self::Output>())
}
```

And `impl_push_for_endian_scalar!` did not override `Push::alignment()`,
inheriting `core::mem::align_of::<T>()` for all primitive scalar types (`bool`,
`u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`, `f32`, `f64`).

On 64-bit targets (`x86_64`, `aarch64`) and 32-bit ARM (`armv7`),
`align_of::<u64>() == 8`, so `align_of::<T>()` happens to equal `size_of::<T>()`.
On 32-bit x86 (`i686`, System V i386 ABI), however, the host ABI alignment of
64-bit scalars (`u64`, `i64`, `f64`) is **4 bytes** (`align_of::<u64>() == 4`),
while their FlatBuffer wire-format size and required wire alignment is **8
bytes** (`size_of::<u64>() == 8`).

As a consequence, on 32-bit x86 (`i686`):
1. `FlatBufferBuilder::push::<u64 / i64 / f64>` only aligns the builder's cursor
   and tracks `min_align` to 4 bytes instead of 8 bytes when writing 64-bit
   table fields or vectors of 64-bit scalars.
2. When a table containing a 64-bit scalar field (`uint64`, `int64`, `double`)
   is serialized on `i686`, the field can be placed at a buffer offset that is
   4-byte aligned but not 8-byte aligned.
3. When the resulting FlatBuffer is verified by C++ `flatbuffers::Verifier`
   (which checks `VerifyField<uint64_t>` with `sizeof(uint64_t) == 8` alignment
   when `FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE` / alignment checks are active)
   or transferred to a 64-bit reader, verification fails or unaligned 64-bit
   reads occur.

Fix `impl_push_for_endian_scalar!` to explicitly implement `Push::alignment()`
using `size_of::<$ty>()` so that all endian scalar types always use their
wire-format byte size as their FlatBuffer alignment across all target
architectures.
2026-11-06 15:15:33 -08:00
Omar AbdelsalamandDerek Bailey f58d5768f1 Pin swift-crypto for the Swift CI matrix (#9412)
The Swift test job pulls in grpc-swift-2 -> grpc-swift-nio-transport ->
swift-nio-ssl -> swift-crypto, and this package ships no Package.resolved,
so that whole graph is resolved afresh on every run. On 2026-10-15 it
resolved swift-crypto 5.0.1 (released three days earlier) and "Test Swift
Linux (6.2)" turned red before a single line of FlatBuffers' Swift code was
compiled:

  Sources/Crypto/HPKE/Ciphersuite/HPKE-AEAD.swift:27:6: error: unknown
  attribute 'nonexhaustive'

5.x declares swift-tools-version 6.2, which is why only the 6.2 job selects
it; the 6.0 and 6.1 jobs prune it and keep building. The 6.2.x toolchains
then reject the `@nonexhaustive` that 5.x uses, a combination swift-crypto
does not exercise because it builds on nightly.

Restrict the test-only graph to 4.0.0 ..< 4.4.0, which resolves to 4.3.0:
the last 4.x release that declares swift-tools-version 6.0 and so builds
with every toolchain in the matrix. 4.4+ asks for 6.1 and would break the 6.0
job, and the whole 4.x line is free of `@nonexhaustive`.

Co-authored-by: Derek Bailey <derekbailey@google.com>
2026-10-26 10:11:08 -07:00
Derek Bailey 7af1efe4b2 Regenerate monster_test_bfbs_generated.h with alignas(uint64_t) (#9434)
Commit 6dda43bb (#9425) added `alignas(uint64_t)` to embedded binary schemas
generated by `flatc --bfbs-gen-embed`. Regenerate `tests/monster_test_bfbs_generated.h`
via `scripts/generate_code.py` to keep checked-in test artifacts in sync and
unblock CI Check Generated Code.

GitOrigin-RevId: 3786479bebd33365edc91aa13388cdf95d7313d9
2026-10-26 09:06:45 -07:00
Derek Bailey 6dda43bbaa Ensure embedded FlatBuffers binary schemas are 8-byte aligned (#9425)
In `src/idl_gen_cpp.cpp`, code generated by `flatc --bfbs-gen-embed` emits `static const uint8_t bfbsData[...] = { ... };`. Because `uint8_t` has 1-byte alignment, the array may be placed at an unaligned address in `.rodata`, triggering alignment traps under Clang UBSan on Arm when accessed via FlatBuffers root accessors.

Add `alignas(uint64_t)` to the generated `bfbsData` array declaration in `GenerateBinarySchema` so embedded binary schemas are 8-byte aligned across all architectures.

PiperOrigin-RevId: 1003962636
2026-10-21 13:37:51 -07:00
Derek Bailey 9a8a511b52 Enable locale-independent strtod_l/strtof_l on Linux glibc (#9424)
Restrict the `__linux__` check for `FLATBUFFERS_LOCALE_INDEPENDENT` in `include/flatbuffers/base.h` to `(!defined(__linux__) || defined(__GLIBC__))` so Linux with glibc enables `strtod_l`/`strtof_l`.

PiperOrigin-RevId: 1002266254
2026-10-21 13:25:17 -07:00
Wouter van Oortmerssen b8431fbcd7 Lobster: change builder size constants (enum -> let)
This is because newer versions of the Lobster compiler reject enums with the same values, and older compilers are fine with the let versions also.
2026-09-14 11:02:13 -07:00
6 changed files with 47 additions and 12 deletions
+11
View File
@@ -75,6 +75,17 @@ extension Array where Element == Package.Dependency {
.package(
url: "https://github.com/grpc/grpc-swift-nio-transport.git",
from: "2.0.0"),
// swift-crypto arrives through grpc-swift-nio-transport -> swift-nio-ssl
// and is otherwise resolved afresh on every build, because this package
// ships no Package.resolved. 5.x asks for swift-tools-version 6.2, so only
// the 6.2 CI job selects it - and then fails to compile it, because 5.x
// uses `@nonexhaustive`, which the 6.2.x toolchains do not accept yet.
// Stay on the last 4.x release that still builds with every toolchain in
// the Swift CI matrix (4.3.0 declares swift-tools-version 6.0; 4.4+ asks
// for 6.1 and would drop the 6.0 job).
.package(
url: "https://github.com/apple/swift-crypto.git",
"4.0.0" ..< "4.4.0"),
]
#endif
}
+1 -1
View File
@@ -271,7 +271,7 @@ namespace flatbuffers {
#if (defined(_MSC_VER) && _MSC_VER >= 1800) || \
(defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__>= 26) || \
(defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 700)) && \
!defined(__Fuchsia__)
!defined(__Fuchsia__) && (!defined(__linux__) || defined(__GLIBC__))
#define FLATBUFFERS_LOCALE_INDEPENDENT 1
#else
#define FLATBUFFERS_LOCALE_INDEPENDENT 0
+8 -9
View File
@@ -24,15 +24,14 @@ class handle:
struct offset:
o:int
enum sizeof:
sz_8 = 1
sz_16 = 2
sz_32 = 4
sz_64 = 8
sz_voffset = 2
sz_uoffset = 4
sz_soffset = 4
sz_metadata_fields = 2
let sz_8 = 1
let sz_16 = 2
let sz_32 = 4
let sz_64 = 8
let sz_voffset = 2
let sz_uoffset = 4
let sz_soffset = 4
let sz_metadata_fields = 2
class builder:
buf = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+25
View File
@@ -83,6 +83,11 @@ macro_rules! impl_push_for_endian_scalar {
unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
emplace_scalar::<$ty>(dst, *self);
}
#[inline]
fn alignment() -> PushAlignment {
PushAlignment::new(size_of::<$ty>())
}
}
};
}
@@ -98,3 +103,23 @@ impl_push_for_endian_scalar!(u64);
impl_push_for_endian_scalar!(i64);
impl_push_for_endian_scalar!(f32);
impl_push_for_endian_scalar!(f64);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn endian_scalar_push_alignment_matches_wire_size() {
assert_eq!(<bool as Push>::alignment().value(), 1);
assert_eq!(<u8 as Push>::alignment().value(), 1);
assert_eq!(<i8 as Push>::alignment().value(), 1);
assert_eq!(<u16 as Push>::alignment().value(), 2);
assert_eq!(<i16 as Push>::alignment().value(), 2);
assert_eq!(<u32 as Push>::alignment().value(), 4);
assert_eq!(<i32 as Push>::alignment().value(), 4);
assert_eq!(<f32 as Push>::alignment().value(), 4);
assert_eq!(<u64 as Push>::alignment().value(), 8);
assert_eq!(<i64 as Push>::alignment().value(), 8);
assert_eq!(<f64 as Push>::alignment().value(), 8);
}
}
+1 -1
View File
@@ -404,7 +404,7 @@ class CppGenerator : public BaseGenerator {
code_ += "struct {{STRUCT_NAME}}BinarySchema {";
code_ += " static const uint8_t *data() {";
code_ += " // Buffer containing the binary schema.";
code_ += " static const uint8_t bfbsData[" +
code_ += " alignas(uint64_t) static const uint8_t bfbsData[" +
NumToString(parser_.builder_.GetSize()) + "] = {";
code_ += binary_schema_hex_text;
code_ += " };";
+1 -1
View File
@@ -12,7 +12,7 @@ namespace Example {
struct MonsterBinarySchema {
static const uint8_t *data() {
// Buffer containing the binary schema.
static const uint8_t bfbsData[14520] = {
alignas(uint64_t) static const uint8_t bfbsData[14520] = {
0x20,0x00,0x00,0x00,0x42,0x46,0x42,0x53,0x00,0x00,0x00,0x00,0x14,0x00,0x20,0x00,0x04,0x00,0x08,0x00,
0x0C,0x00,0x10,0x00,0x14,0x00,0x18,0x00,0x00,0x00,0x1C,0x00,0x14,0x00,0x00,0x00,0x58,0x00,0x00,0x00,
0x34,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x70,0x0D,0x00,0x00,0x08,0x00,0x00,0x00,