Skip to content

Commit 703279e

Browse files
fergushendersonJochen Parmentier
authored andcommitted
Avoid ODR violations with flatbuffers::Verifier. (google#8274)
Fix "One Definition Rule" violation when using flatbuffers::Verifier with FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE defined in some compilation units and not defined in other compilation units. The fix is to make Verifier a template class, with a boolean template parameter replacing the "#ifdef" conditionals; to rename it as VerifierTemplate; and then to use "#ifdef" only for a "using" declaration that defines the original name Verifier an an alias for the instantiated template. In this way, even if FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE is defined in some compilation units and not in others, as long as clients only reference flatbuffers::Verifier in .cc files, not header files, there will be no ODR violation, since the only part whose definition varies is the "using" declaration, which does not have external linkage. There is still some possibility of clients creating ODR violations if the client header files (rather than .cc files) reference flatbuffers::Verifier. To avoid that, this change also deprecates FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE, and instead introduces flatbuffers::SizeVerifier as a public name for the template instance with the boolean parameter set to true, so that clients don't need to define the macro at all.
1 parent ec34bcd commit 703279e

File tree

1 file changed

+70
-38
lines changed

1 file changed

+70
-38
lines changed

include/flatbuffers/verifier.h

Lines changed: 70 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
namespace flatbuffers {
2424

2525
// Helper class to verify the integrity of a FlatBuffer
26-
class Verifier FLATBUFFERS_FINAL_CLASS {
26+
template <bool TrackVerifierBufferSize>
27+
class VerifierTemplate FLATBUFFERS_FINAL_CLASS {
2728
public:
2829
struct Options {
2930
// The maximum nesting of tables and vectors before we call it invalid.
@@ -40,17 +41,18 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
4041
bool assert = false;
4142
};
4243

43-
explicit Verifier(const uint8_t *const buf, const size_t buf_len,
44-
const Options &opts)
44+
explicit VerifierTemplate(const uint8_t *const buf, const size_t buf_len,
45+
const Options &opts)
4546
: buf_(buf), size_(buf_len), opts_(opts) {
4647
FLATBUFFERS_ASSERT(size_ < opts.max_size);
4748
}
4849

49-
// Deprecated API, please construct with Verifier::Options.
50-
Verifier(const uint8_t *const buf, const size_t buf_len,
51-
const uoffset_t max_depth = 64, const uoffset_t max_tables = 1000000,
52-
const bool check_alignment = true)
53-
: Verifier(buf, buf_len, [&] {
50+
// Deprecated API, please construct with VerifierTemplate::Options.
51+
VerifierTemplate(const uint8_t *const buf, const size_t buf_len,
52+
const uoffset_t max_depth = 64,
53+
const uoffset_t max_tables = 1000000,
54+
const bool check_alignment = true)
55+
: VerifierTemplate(buf, buf_len, [&] {
5456
Options opts;
5557
opts.max_depth = max_depth;
5658
opts.max_tables = max_tables;
@@ -62,25 +64,25 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
6264
bool Check(const bool ok) const {
6365
// clang-format off
6466
#ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE
65-
if (opts_.assert) { FLATBUFFERS_ASSERT(ok); }
66-
#endif
67-
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
68-
if (!ok)
69-
upper_bound_ = 0;
67+
if (opts_.assert) { FLATBUFFERS_ASSERT(ok); }
7068
#endif
7169
// clang-format on
70+
if (TrackVerifierBufferSize) {
71+
if (!ok) {
72+
upper_bound_ = 0;
73+
}
74+
}
7275
return ok;
7376
}
7477

7578
// Verify any range within the buffer.
7679
bool Verify(const size_t elem, const size_t elem_len) const {
77-
// clang-format off
78-
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
80+
if (TrackVerifierBufferSize) {
7981
auto upper_bound = elem + elem_len;
80-
if (upper_bound_ < upper_bound)
82+
if (upper_bound_ < upper_bound) {
8183
upper_bound_ = upper_bound;
82-
#endif
83-
// clang-format on
84+
}
85+
}
8486
return Check(elem_len < size_ && elem <= size_ - elem_len);
8587
}
8688

@@ -210,14 +212,14 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
210212

211213
// Call T::Verify, which must be in the generated code for this type.
212214
const auto o = VerifyOffset<uoffset_t>(start);
213-
return Check(o != 0) &&
214-
reinterpret_cast<const T *>(buf_ + start + o)->Verify(*this)
215-
// clang-format off
216-
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
217-
&& GetComputedSize()
218-
#endif
219-
;
220-
// clang-format on
215+
if (!Check(o != 0)) return false;
216+
if (!(reinterpret_cast<const T *>(buf_ + start + o)->Verify(*this))) {
217+
return false;
218+
}
219+
if (TrackVerifierBufferSize) {
220+
if (GetComputedSize() == 0) return false;
221+
}
222+
return true;
221223
}
222224

223225
template<typename T, int &..., typename SizeT>
@@ -232,7 +234,8 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
232234
// If there is a nested buffer, it must be greater than the min size.
233235
if (!Check(buf->size() >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false;
234236

235-
Verifier nested_verifier(buf->data(), buf->size(), opts_);
237+
VerifierTemplate<TrackVerifierBufferSize> nested_verifier(
238+
buf->data(), buf->size(), opts_);
236239
return nested_verifier.VerifyBuffer<T>(identifier);
237240
}
238241

@@ -286,21 +289,27 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
286289
return true;
287290
}
288291

289-
// Returns the message size in bytes
292+
// Returns the message size in bytes.
293+
//
294+
// This should only be called after first calling VerifyBuffer or
295+
// VerifySizePrefixedBuffer.
296+
//
297+
// This method should only be called for VerifierTemplate instances
298+
// where the TrackVerifierBufferSize template parameter is true,
299+
// i.e. for SizeVerifier. For instances where TrackVerifierBufferSize
300+
// is false, this fails at runtime or returns zero.
290301
size_t GetComputedSize() const {
291-
// clang-format off
292-
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
302+
if (TrackVerifierBufferSize) {
293303
uintptr_t size = upper_bound_;
294304
// Align the size to uoffset_t
295305
size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
296306
return (size > size_) ? 0 : size;
297-
#else
298-
// Must turn on FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE for this to work.
299-
(void)upper_bound_;
300-
FLATBUFFERS_ASSERT(false);
301-
return 0;
302-
#endif
303-
// clang-format on
307+
}
308+
// Must use SizeVerifier, or (deprecated) turn on
309+
// FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE, for this to work.
310+
(void)upper_bound_;
311+
FLATBUFFERS_ASSERT(false);
312+
return 0;
304313
}
305314

306315
std::vector<uint8_t> *GetFlexReuseTracker() { return flex_reuse_tracker_; }
@@ -323,10 +332,33 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
323332

324333
// Specialization for 64-bit offsets.
325334
template<>
326-
inline size_t Verifier::VerifyOffset<uoffset64_t>(const size_t start) const {
335+
template<>
336+
inline size_t VerifierTemplate<false>::VerifyOffset<uoffset64_t>(
337+
const size_t start) const {
338+
return VerifyOffset<uoffset64_t, soffset64_t>(start);
339+
}
340+
template<>
341+
template<>
342+
inline size_t VerifierTemplate<true>::VerifyOffset<uoffset64_t>(
343+
const size_t start) const {
327344
return VerifyOffset<uoffset64_t, soffset64_t>(start);
328345
}
329346

347+
// Instance of VerifierTemplate that supports GetComputedSize().
348+
using SizeVerifier = VerifierTemplate</*TrackVerifierBufferSize = */ true>;
349+
350+
// The FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE build configuration macro is
351+
// deprecated, and should not be defined, since it is easy to misuse in ways
352+
// that result in ODR violations. Rather than using Verifier and defining
353+
// FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE, please use SizeVerifier instead.
354+
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE // Deprecated, see above.
355+
using Verifier = SizeVerifier;
356+
#else
357+
// Instance of VerifierTemplate that is slightly faster, but does not
358+
// support GetComputedSize().
359+
using Verifier = VerifierTemplate</*TrackVerifierBufferSize = */ false>;
360+
#endif
361+
330362
} // namespace flatbuffers
331363

332364
#endif // FLATBUFFERS_VERIFIER_H_

0 commit comments

Comments
 (0)