mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-24 22:56:11 +00:00
Added functionality to obtain a buffer pointer from a root.
Change-Id: Ia63e41d0304e8668ea4ce09a4c31dd999eb96994 Tested: on Linux. Bug: 32218623
This commit is contained in:
@@ -130,6 +130,9 @@ typedef uintmax_t largest_scalar_t;
|
|||||||
// In 32bits, this evaluates to 2GB - 1
|
// In 32bits, this evaluates to 2GB - 1
|
||||||
#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(soffset_t) * 8 - 1)) - 1)
|
#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(soffset_t) * 8 - 1)) - 1)
|
||||||
|
|
||||||
|
// We support aligning the contents of buffers up to this size.
|
||||||
|
#define FLATBUFFERS_MAX_ALIGNMENT 16
|
||||||
|
|
||||||
#ifndef FLATBUFFERS_CPP98_STL
|
#ifndef FLATBUFFERS_CPP98_STL
|
||||||
// Pointer to relinquished memory.
|
// Pointer to relinquished memory.
|
||||||
typedef std::unique_ptr<uint8_t, std::function<void(uint8_t * /* unused */)>>
|
typedef std::unique_ptr<uint8_t, std::function<void(uint8_t * /* unused */)>>
|
||||||
@@ -1499,11 +1502,15 @@ class Struct FLATBUFFERS_FINAL_CLASS {
|
|||||||
// omitted and added at will, but uses an extra indirection to read.
|
// omitted and added at will, but uses an extra indirection to read.
|
||||||
class Table {
|
class Table {
|
||||||
public:
|
public:
|
||||||
|
const uint8_t *GetVTable() const {
|
||||||
|
return data_ - ReadScalar<soffset_t>(data_);
|
||||||
|
}
|
||||||
|
|
||||||
// This gets the field offset for any of the functions below it, or 0
|
// This gets the field offset for any of the functions below it, or 0
|
||||||
// if the field was not present.
|
// if the field was not present.
|
||||||
voffset_t GetOptionalFieldOffset(voffset_t field) const {
|
voffset_t GetOptionalFieldOffset(voffset_t field) const {
|
||||||
// The vtable offset is always at the start.
|
// The vtable offset is always at the start.
|
||||||
auto vtable = data_ - ReadScalar<soffset_t>(data_);
|
auto vtable = GetVTable();
|
||||||
// The first element is the size of the vtable (fields + type id + itself).
|
// The first element is the size of the vtable (fields + type id + itself).
|
||||||
auto vtsize = ReadScalar<voffset_t>(vtable);
|
auto vtsize = ReadScalar<voffset_t>(vtable);
|
||||||
// If the field we're accessing is outside the vtable, we're reading older
|
// If the field we're accessing is outside the vtable, we're reading older
|
||||||
@@ -1556,8 +1563,6 @@ class Table {
|
|||||||
return const_cast<Table *>(this)->GetAddressOf(field);
|
return const_cast<Table *>(this)->GetAddressOf(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *GetVTable() { return data_ - ReadScalar<soffset_t>(data_); }
|
|
||||||
|
|
||||||
bool CheckField(voffset_t field) const {
|
bool CheckField(voffset_t field) const {
|
||||||
return GetOptionalFieldOffset(field) != 0;
|
return GetOptionalFieldOffset(field) != 0;
|
||||||
}
|
}
|
||||||
@@ -1567,7 +1572,7 @@ class Table {
|
|||||||
bool VerifyTableStart(Verifier &verifier) const {
|
bool VerifyTableStart(Verifier &verifier) const {
|
||||||
// Check the vtable offset.
|
// Check the vtable offset.
|
||||||
if (!verifier.Verify<soffset_t>(data_)) return false;
|
if (!verifier.Verify<soffset_t>(data_)) return false;
|
||||||
auto vtable = data_ - ReadScalar<soffset_t>(data_);
|
auto vtable = GetVTable();
|
||||||
// Check the vtable size field, then check vtable fits in its entirety.
|
// Check the vtable size field, then check vtable fits in its entirety.
|
||||||
return verifier.VerifyComplexity() &&
|
return verifier.VerifyComplexity() &&
|
||||||
verifier.Verify<voffset_t>(vtable) &&
|
verifier.Verify<voffset_t>(vtable) &&
|
||||||
@@ -1602,6 +1607,44 @@ class Table {
|
|||||||
uint8_t data_[1];
|
uint8_t data_[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @brief This can compute the start of a FlatBuffer from a root pointer, i.e.
|
||||||
|
/// it is the opposite transformation of GetRoot().
|
||||||
|
/// This may be useful if you want to pass on a root and have the recipient
|
||||||
|
/// delete the buffer afterwards.
|
||||||
|
inline const uint8_t *GetBufferStartFromRootPointer(const void *root) {
|
||||||
|
auto table = reinterpret_cast<const Table *>(root);
|
||||||
|
auto vtable = table->GetVTable();
|
||||||
|
// Either the vtable is before the root or after the root.
|
||||||
|
auto start = std::min(vtable, reinterpret_cast<const uint8_t *>(root));
|
||||||
|
// Align to at least sizeof(uoffset_t).
|
||||||
|
start = reinterpret_cast<const uint8_t *>(
|
||||||
|
reinterpret_cast<uintptr_t>(start) & ~(sizeof(uoffset_t) - 1));
|
||||||
|
// Additionally, there may be a file_identifier in the buffer, and the root
|
||||||
|
// offset. The buffer may have been aligned to any size between
|
||||||
|
// sizeof(uoffset_t) and FLATBUFFERS_MAX_ALIGNMENT (see "force_align").
|
||||||
|
// Sadly, the exact alignment is only known when constructing the buffer,
|
||||||
|
// since it depends on the presence of values with said alignment properties.
|
||||||
|
// So instead, we simply look at the next uoffset_t values (root,
|
||||||
|
// file_identifier, and alignment padding) to see which points to the root.
|
||||||
|
// None of the other values can "impersonate" the root since they will either
|
||||||
|
// be 0 or four ASCII characters.
|
||||||
|
static_assert(FlatBufferBuilder::kFileIdentifierLength == sizeof(uoffset_t),
|
||||||
|
"file_identifier is assumed to be the same size as uoffset_t");
|
||||||
|
for (auto possible_roots = FLATBUFFERS_MAX_ALIGNMENT / sizeof(uoffset_t) + 1;
|
||||||
|
possible_roots;
|
||||||
|
possible_roots--) {
|
||||||
|
start -= sizeof(uoffset_t);
|
||||||
|
if (ReadScalar<uoffset_t>(start) + start ==
|
||||||
|
reinterpret_cast<const uint8_t *>(root)) return start;
|
||||||
|
}
|
||||||
|
// We didn't find the root, either the "root" passed isn't really a root,
|
||||||
|
// or the buffer is corrupt.
|
||||||
|
// Assert, because calling this function with bad data may cause reads
|
||||||
|
// outside of buffer boundaries.
|
||||||
|
assert(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Base class for native objects (FlatBuffer data de-serialized into native
|
// Base class for native objects (FlatBuffer data de-serialized into native
|
||||||
// C++ data structures).
|
// C++ data structures).
|
||||||
// Contains no functionality, purely documentative.
|
// Contains no functionality, purely documentative.
|
||||||
|
|||||||
@@ -1352,10 +1352,11 @@ CheckedError Parser::ParseDecl() {
|
|||||||
auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
|
auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
|
||||||
if (force_align->type.base_type != BASE_TYPE_INT ||
|
if (force_align->type.base_type != BASE_TYPE_INT ||
|
||||||
align < struct_def->minalign ||
|
align < struct_def->minalign ||
|
||||||
align > 16 ||
|
align > FLATBUFFERS_MAX_ALIGNMENT ||
|
||||||
align & (align - 1))
|
align & (align - 1))
|
||||||
return Error("force_align must be a power of two integer ranging from the"
|
return Error("force_align must be a power of two integer ranging from the"
|
||||||
"struct\'s natural alignment to 16");
|
"struct\'s natural alignment to " +
|
||||||
|
NumToString(FLATBUFFERS_MAX_ALIGNMENT));
|
||||||
struct_def->minalign = align;
|
struct_def->minalign = align;
|
||||||
}
|
}
|
||||||
struct_def->PadLastField(struct_def->minalign);
|
struct_def->PadLastField(struct_def->minalign);
|
||||||
|
|||||||
@@ -180,7 +180,8 @@ class ResizeContext {
|
|||||||
// Check if the range between first (lower address) and second straddles
|
// Check if the range between first (lower address) and second straddles
|
||||||
// the insertion point. If it does, change the offset at offsetloc (of
|
// the insertion point. If it does, change the offset at offsetloc (of
|
||||||
// type T, with direction D).
|
// type T, with direction D).
|
||||||
template<typename T, int D> void Straddle(void *first, void *second,
|
template<typename T, int D> void Straddle(const void *first,
|
||||||
|
const void *second,
|
||||||
void *offsetloc) {
|
void *offsetloc) {
|
||||||
if (first <= startptr_ && second >= startptr_) {
|
if (first <= startptr_ && second >= startptr_) {
|
||||||
WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
|
WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
|
||||||
@@ -194,9 +195,9 @@ class ResizeContext {
|
|||||||
// resize actually happens.
|
// resize actually happens.
|
||||||
// This must be checked for every offset, since we can't know which offsets
|
// This must be checked for every offset, since we can't know which offsets
|
||||||
// will straddle and which won't.
|
// will straddle and which won't.
|
||||||
uint8_t &DagCheck(void *offsetloc) {
|
uint8_t &DagCheck(const void *offsetloc) {
|
||||||
auto dag_idx = reinterpret_cast<uoffset_t *>(offsetloc) -
|
auto dag_idx = reinterpret_cast<const uoffset_t *>(offsetloc) -
|
||||||
reinterpret_cast<uoffset_t *>(buf_.data());
|
reinterpret_cast<const uoffset_t *>(buf_.data());
|
||||||
return dag_check_[dag_idx];
|
return dag_check_[dag_idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -270,6 +270,9 @@ void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length,
|
|||||||
// Checking for presence of fields:
|
// Checking for presence of fields:
|
||||||
TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_HP), true);
|
TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_HP), true);
|
||||||
TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_MANA), false);
|
TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_MANA), false);
|
||||||
|
|
||||||
|
// Obtaining a buffer from a root:
|
||||||
|
TEST_EQ(GetBufferStartFromRootPointer(monster), flatbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change a FlatBuffer in-place, after it has been constructed.
|
// Change a FlatBuffer in-place, after it has been constructed.
|
||||||
|
|||||||
Reference in New Issue
Block a user