From d094b03d690de8841d900eb401936cd2e327c21b Mon Sep 17 00:00:00 2001 From: emkornfield Date: Sun, 19 May 2019 23:50:32 -0700 Subject: [PATCH 1/2] Fix Undefined behavior for zero length vectors --- include/flatbuffers/flatbuffers.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 6966cb0af6..f07d5a5569 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -803,7 +803,12 @@ class vector_downward { uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; } void push(const uint8_t *bytes, size_t num) { - memcpy(make_space(num), bytes, num); + // CreateVector above, can pass through a nullptr for bytes + // for empty vectors. Passing nullptr to memcpy is undefined + // behavior. + if (num > 0) { + memcpy(make_space(num), bytes, num); + } } // Specialized version of push() that avoids memcpy call for small data. From acacd4dab8c12c395dee0cdf6e497b4ac4132f70 Mon Sep 17 00:00:00 2001 From: Micah Kornfield Date: Thu, 23 May 2019 21:15:23 -0700 Subject: [PATCH 2/2] Change fix for UBSan --- include/flatbuffers/flatbuffers.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index f07d5a5569..855abc4df4 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -803,12 +803,7 @@ class vector_downward { uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; } void push(const uint8_t *bytes, size_t num) { - // CreateVector above, can pass through a nullptr for bytes - // for empty vectors. Passing nullptr to memcpy is undefined - // behavior. - if (num > 0) { - memcpy(make_space(num), bytes, num); - } + memcpy(make_space(num), bytes, num); } // Specialized version of push() that avoids memcpy call for small data. @@ -897,10 +892,16 @@ inline voffset_t FieldIndexToOffset(voffset_t field_id) { template const T *data(const std::vector &v) { - return v.empty() ? nullptr : &v.front(); + // Eventually the returned pointer gets passed down to memcpy, so + // we need it to be non-null to avoid undefined behavior. + static uint8_t t; + return v.empty() ? reinterpret_cast(&t) : &v.front(); } template T *data(std::vector &v) { - return v.empty() ? nullptr : &v.front(); + // Eventually the returned pointer gets passed down to memcpy, so + // we need it to be non-null to avoid undefined behavior. + static uint8_t t; + return v.empty() ? reinterpret_cast(&t) : &v.front(); } /// @endcond