Skip to content

Commit fd3c4ae

Browse files
authored
Add FLATCC_ENFORCE_ALIGNED_EMPTY_VECTORS (#289)
Work around issue where other builders do not align empty vectors correctly.
1 parent 4b21380 commit fd3c4ae

File tree

4 files changed

+43
-27
lines changed

4 files changed

+43
-27
lines changed

CMakeLists.txt

+11
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ option (FLATCC_DEBUG_VERIFY
7777
option (FLATCC_TRACE_VERIFY
7878
"assert on verify failure in runtime lib" OFF)
7979

80+
# Some producers allow empty vectors to be misaligned.
81+
# The following setting will cause the verifier to require the index 0
82+
# position to be element aligned even if the vector is empty (otherwise that
83+
# position is only required to be aligned to the preceding size field).
84+
option (FLATCC_ENFORCE_ALIGNED_EMPTY_VECTORS
85+
"verify includes full alignment check for empty vectors" OFF)
86+
8087
# Reflection is the compilers ability to generate binary schema output
8188
# (.bfbs files). This requires using generated code from
8289
# `reflection.fbs`. During development it may not be possible to
@@ -141,6 +148,10 @@ if (FLATCC_TRACE_VERIFY)
141148
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFLATCC_TRACE_VERIFY=1")
142149
endif()
143150

151+
if (FLATCC_ENFORCE_ALIGNED_EMPTY_VECTORS)
152+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFLATCC_ENFORCE_ALIGNED_EMPTY_VECTORS=1")
153+
endif()
154+
144155

145156
if (FLATCC_REFLECTION)
146157
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFLATCC_REFLECTION=1")

README.md

+15-12
Original file line numberDiff line numberDiff line change
@@ -1164,18 +1164,20 @@ sufficient, but for example standard 32-bit Windows only allocates on an
11641164
aligned fields.
11651165

11661166
NOTE: as of August 2024 it has been discovered that C++ writer code has been
1167-
aligning empty vectors to the size field only, even if elements where larger,
1168-
like the double type of size 8. This would cause the FlatCC verifier to
1169-
(correctly) reject these vectors because it would result in an invalid C pointer
1170-
type on some architectures. However, because this has been in effect for over
1171-
10 years, the consensus is to have verifiers tolerate this behaviour even if
1172-
C++ will eventually fix this issue. The FlatCC verifier will be updated to
1173-
accept such buffers by default with a compile time flag to enforce the strict
1174-
behaviour as well. In principle the misaligned vectors can lead potentially
1175-
lead to undefined behaviour in agressively optimized C compilers. As of now
1176-
it appears to be safe to read such buffers on common platforms and it is
1177-
preferably to avoid additional runtime reader overhead to deal with this.
1178-
For more, see [FlatCC #287], [Google Flatbuffers #8374].
1167+
aligning empty vectors to the size field only, even if elements require
1168+
greater alignment like the double type which requires 8. This would cause the
1169+
FlatCC verifier to (correctly) reject these vectors because it would result
1170+
in an invalid C pointer type on some architectures. However, because this has
1171+
been in effect for over 10 years, the consensus is to have verifiers tolerate
1172+
this behaviour even if C++ will eventually fix this issue. The FlatCC
1173+
verifier has been updated to accept such buffers by default with an optional
1174+
compile time flag to enforce the strict behaviour as well
1175+
(`FLATCC_ENFORCE_ALIGNED_EMPTY_VECTORS`). In principle the misaligned vectors
1176+
can lead potentially lead to undefined behaviour in agressively optimized C
1177+
compilers. As of now it appears to be safe to read such buffers on common
1178+
platforms and it is preferable to avoid additional runtime reader overhead to
1179+
deal with this. For more, see [FlatCC #287], [Google Flatbuffers #8374],
1180+
[FlatCC #289].
11791181

11801182

11811183
### Potential Name Conflicts
@@ -2718,3 +2720,4 @@ See [Benchmarks]
27182720
[WebKit Style]: https://webkit.org/code-style-guidelines/
27192721
[FlatCC #287]: https://github.com/dvidelabs/flatcc/issues/287
27202722
[Google Flatbuffers #8374]: https://github.com/google/flatbuffers/issues/8374
2723+
[FlatCC #289]: https://github.com/dvidelabs/flatcc/issues/289

include/flatcc/flatcc_rtconfig.h

+9
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@ extern "C" {
6363
#define FLATCC_TRACE_VERIFY 0
6464
#endif
6565

66+
/*
67+
* Some producers allow empty vectors to be misaligned.
68+
* The following setting will cause the verifier to require the index 0
69+
* position to be element aligned even if the vector is empty (otherwise that
70+
* position is only required to be aligned to the preceding size field).
71+
*/
72+
#if !defined(FLATCC_ENFORCE_ALIGNED_EMPTY_VECTORS)
73+
#define FLATCC_ENFORCE_ALIGNED_EMPTY_VECTORS 0
74+
#endif
6675

6776
/*
6877
* Limit recursion level for tables. Actual level may be deeper

src/runtime/verifier.c

+8-15
Original file line numberDiff line numberDiff line change
@@ -135,20 +135,6 @@ static inline int check_header(uoffset_t end, uoffset_t base, uoffset_t offset)
135135
return k > base && k + offset_size <= end && !(k & (offset_size - 1));
136136
}
137137

138-
static inline int check_aligned_header(uoffset_t end, uoffset_t base, uoffset_t offset, uint16_t align)
139-
{
140-
uoffset_t k = base + offset;
141-
142-
if (uoffset_size <= voffset_size && k + offset_size < k) {
143-
return 0;
144-
}
145-
/* Alignment refers to element 0 and header must also be aligned. */
146-
align = align < uoffset_size ? uoffset_size : align;
147-
148-
/* Note to self: the builder can also use the mask OR trick to propagate `min_align`. */
149-
return k > base && k + offset_size <= end && !((k + offset_size) & ((offset_size - 1) | (align - 1u)));
150-
}
151-
152138
static inline int verify_struct(uoffset_t end, uoffset_t base, uoffset_t offset, uoffset_t size, uint16_t align)
153139
{
154140
/* Structs can have zero size so `end` is a valid value. */
@@ -278,10 +264,17 @@ static inline int verify_vector(const void *buf, uoffset_t end, uoffset_t base,
278264
{
279265
uoffset_t n;
280266

281-
verify(check_aligned_header(end, base, offset, align), flatcc_verify_error_vector_header_out_of_range_or_unaligned);
267+
verify(check_header(end, base, offset), flatcc_verify_error_vector_header_out_of_range_or_unaligned);
282268
base += offset;
269+
283270
n = read_uoffset(buf, base);
284271
base += offset_size;
272+
273+
#if !FLATCC_ENFORCE_ALIGNED_EMPTY_VECTORS
274+
/* This is due to incorrect buffers from other builders than cannot easily be ignored. */
275+
align = n == 0 ? uoffset_size : align;
276+
#endif
277+
verify(!(base & ((align - 1u) | (uoffset_size - 1u))), flatcc_verify_error_vector_header_out_of_range_or_unaligned);
285278
/* `n * elem_size` can overflow uncontrollably otherwise. */
286279
verify(n <= max_count, flatcc_verify_error_vector_count_exceeds_representable_vector_size);
287280
verify(end - base >= n * elem_size, flatcc_verify_error_vector_out_of_range);

0 commit comments

Comments
 (0)