Fixed vtable duplication for binary annotator (#7809)

This commit is contained in:
Derek Bailey
2023-02-02 12:39:39 -06:00
committed by GitHub
parent f838017860
commit 0fb5519585
28 changed files with 6807 additions and 6788 deletions

View File

@@ -196,14 +196,22 @@ uint64_t BinaryAnnotator::BuildHeader(const uint64_t header_offset) {
return root_table_offset.value();
}
void BinaryAnnotator::BuildVTable(const uint64_t vtable_offset,
const reflection::Object *const table,
const uint64_t offset_of_referring_table) {
// First see if we have used this vtable before, if so skip building it again.
auto it = vtables_.find(vtable_offset);
if (it != vtables_.end()) { return; }
BinaryAnnotator::VTable *BinaryAnnotator::GetOrBuildVTable(
const uint64_t vtable_offset, const reflection::Object *const table,
const uint64_t offset_of_referring_table) {
// Get a list of vtables (if any) already defined at this offset.
std::list<VTable> &vtables = vtables_[vtable_offset];
if (ContainsSection(vtable_offset)) { return; }
// See if this vtable for the table type has been generated before.
for (VTable &vtable : vtables) {
if (vtable.referring_table == table) { return &vtable; }
}
// If we are trying to make a new vtable and it is already encompassed by
// another binary section, something is corrupted.
if (vtables.empty() && ContainsSection(vtable_offset)) { return nullptr; }
const std::string referring_table_name = table->name()->str();
BinaryRegionComment vtable_size_comment;
vtable_size_comment.type = BinaryRegionCommentType::VTableSize;
@@ -217,11 +225,11 @@ void BinaryAnnotator::BuildVTable(const uint64_t vtable_offset,
AddSection(vtable_offset,
MakeSingleRegionBinarySection(
table->name()->str(), BinarySectionType::VTable,
referring_table_name, BinarySectionType::VTable,
MakeBinaryRegion(vtable_offset, remaining,
BinaryRegionType::Unknown, remaining, 0,
vtable_size_comment)));
return;
return nullptr;
}
// Vtables start with the size of the vtable
@@ -232,23 +240,23 @@ void BinaryAnnotator::BuildVTable(const uint64_t vtable_offset,
// The vtable_size points to off the end of the binary.
AddSection(vtable_offset,
MakeSingleRegionBinarySection(
table->name()->str(), BinarySectionType::VTable,
referring_table_name, BinarySectionType::VTable,
MakeBinaryRegion(vtable_offset, sizeof(uint16_t),
BinaryRegionType::Uint16, 0, 0,
vtable_size_comment)));
return;
return nullptr;
} else if (vtable_size < 2 * sizeof(uint16_t)) {
SetError(vtable_size_comment, BinaryRegionStatus::ERROR_LENGTH_TOO_SHORT,
"4");
// The size includes itself and the table size which are both uint16_t.
AddSection(vtable_offset,
MakeSingleRegionBinarySection(
table->name()->str(), BinarySectionType::VTable,
referring_table_name, BinarySectionType::VTable,
MakeBinaryRegion(vtable_offset, sizeof(uint16_t),
BinaryRegionType::Uint16, 0, 0,
vtable_size_comment)));
return;
return nullptr;
}
std::vector<BinaryRegion> regions;
@@ -272,11 +280,11 @@ void BinaryAnnotator::BuildVTable(const uint64_t vtable_offset,
"2");
AddSection(offset, MakeSingleRegionBinarySection(
table->name()->str(), BinarySectionType::VTable,
referring_table_name, BinarySectionType::VTable,
MakeBinaryRegion(
offset, remaining, BinaryRegionType::Unknown,
remaining, 0, ref_table_len_comment)));
return;
return nullptr;
}
// Then they have the size of the table they reference.
@@ -395,7 +403,7 @@ void BinaryAnnotator::BuildVTable(const uint64_t vtable_offset,
(vtable_size - sizeof(uint16_t) - sizeof(uint16_t)) / sizeof(uint16_t);
// Prevent a bad binary from declaring a really large vtable_size, that we can
// not indpendently verify.
// not independently verify.
expectant_vtable_fields = std::min(
static_cast<uint16_t>(fields_processed * 3), expectant_vtable_fields);
@@ -427,15 +435,26 @@ void BinaryAnnotator::BuildVTable(const uint64_t vtable_offset,
field_comment));
}
sections_[vtable_offset] = MakeBinarySection(
table->name()->str(), BinarySectionType::VTable, std::move(regions));
// If we have never added this vtable before record the Binary section.
if (vtables.empty()) {
sections_[vtable_offset] = MakeBinarySection(
referring_table_name, BinarySectionType::VTable, std::move(regions));
} else {
// Add the current table name to the name of the section.
sections_[vtable_offset].name += ", " + referring_table_name;
}
VTable vtable;
vtable.referring_table = table;
vtable.fields = std::move(fields);
vtable.table_size = table_size;
vtable.vtable_size = vtable_size;
vtables_[vtable_offset] = vtable;
// Add this vtable to the collection of vtables at this offset.
vtables.push_back(std::move(vtable));
// Return the vtable we just added.
return &vtables.back();
}
void BinaryAnnotator::BuildTable(const uint64_t table_offset,
@@ -491,19 +510,17 @@ void BinaryAnnotator::BuildTable(const uint64_t table_offset,
// Parse the vtable first so we know what the rest of the fields in the table
// are.
BuildVTable(vtable_offset, table, table_offset);
const VTable *const vtable =
GetOrBuildVTable(vtable_offset, table, table_offset);
auto vtable_entry = vtables_.find(vtable_offset);
if (vtable_entry == vtables_.end()) {
if (vtable == nullptr) {
// There is no valid vtable for this table, so we cannot process the rest of
// the table entries.
return;
}
const VTable &vtable = vtable_entry->second;
// This is the size and length of this table.
const uint16_t table_size = vtable.table_size;
const uint16_t table_size = vtable->table_size;
uint64_t table_end_offset = table_offset + table_size;
if (!IsValidOffset(table_end_offset - 1)) {
@@ -516,7 +533,7 @@ void BinaryAnnotator::BuildTable(const uint64_t table_offset,
// not by their IDs. So copy them over to another vector that we can sort on
// the offset_from_table property.
std::vector<VTable::Entry> fields;
for (const auto &vtable_field : vtable.fields) {
for (const auto &vtable_field : vtable->fields) {
fields.push_back(vtable_field.second);
}
@@ -707,7 +724,8 @@ void BinaryAnnotator::BuildTable(const uint64_t table_offset,
regions.push_back(MakeBinaryRegion(
field_offset, sizeof(uint32_t), BinaryRegionType::UOffset, 0,
offset_of_next_item, offset_field_comment));
BuildVector(offset_of_next_item, table, field, table_offset, vtable);
BuildVector(offset_of_next_item, table, field, table_offset,
vtable->fields);
} break;
case reflection::BaseType::Union: {
@@ -716,8 +734,8 @@ void BinaryAnnotator::BuildTable(const uint64_t table_offset,
// The union type field is always one less than the union itself.
const uint16_t union_type_id = field->id() - 1;
auto vtable_field = vtable.fields.find(union_type_id);
if (vtable_field == vtable.fields.end()) {
auto vtable_field = vtable->fields.find(union_type_id);
if (vtable_field == vtable->fields.end()) {
// TODO(dbaileychess): need to capture this error condition.
break;
}
@@ -959,11 +977,10 @@ void BinaryAnnotator::BuildString(const uint64_t string_offset,
BinarySectionType::String, std::move(regions)));
}
void BinaryAnnotator::BuildVector(const uint64_t vector_offset,
const reflection::Object *const table,
const reflection::Field *const field,
const uint64_t parent_table_offset,
const VTable &vtable) {
void BinaryAnnotator::BuildVector(
const uint64_t vector_offset, const reflection::Object *const table,
const reflection::Field *const field, const uint64_t parent_table_offset,
const std::map<uint16_t, VTable::Entry> vtable_fields) {
if (ContainsSection(vector_offset)) { return; }
BinaryRegionComment vector_length_comment;
@@ -1011,7 +1028,7 @@ void BinaryAnnotator::BuildVector(const uint64_t vector_offset,
regions.push_back(MakeBinaryRegion(vector_offset, sizeof(uint32_t),
BinaryRegionType::Uint32, 0, 0,
vector_length_comment));
// Consume the vector length offset.
uint64_t offset = vector_offset + sizeof(uint32_t);
switch (field->type()->element()) {
@@ -1079,6 +1096,7 @@ void BinaryAnnotator::BuildVector(const uint64_t vector_offset,
offset, sizeof(uint32_t), BinaryRegionType::UOffset, 0,
table_offset, vector_object_comment));
// Consume the offset to the table.
offset += sizeof(uint32_t);
BuildTable(table_offset, BinarySectionType::Table, object);
@@ -1135,8 +1153,8 @@ void BinaryAnnotator::BuildVector(const uint64_t vector_offset,
// location.
const uint16_t union_type_vector_id = field->id() - 1;
auto vtable_entry = vtable.fields.find(union_type_vector_id);
if (vtable_entry == vtable.fields.end()) {
auto vtable_entry = vtable_fields.find(union_type_vector_id);
if (vtable_entry == vtable_fields.end()) {
// TODO(dbaileychess): need to capture this error condition.
break;
}