handle overlapping structures in check-structures-sanity better

update structures
develop
Ben Lubar 2020-03-12 22:16:30 -05:00
parent d456e3db7a
commit 39486083f5
No known key found for this signature in database
GPG Key ID: 92939677AB59EDA4
4 changed files with 106 additions and 63 deletions

@ -1 +1 @@
Subproject commit 08e114638f3785fd2bee01714be9eca3c1bc99a5
Subproject commit 8ec203292e0aff9dce2a514d4bee01ba722f16de

@ -44,7 +44,7 @@ struct CheckedStructure
CheckedStructure(const struct_field_info *);
size_t full_size() const;
const struct_field_info *find_field_at_offset_with_type(size_t, const CheckedStructure &) const;
bool has_type_at_offset(const CheckedStructure &, size_t) const;
};
#define MIN_SIZE_FOR_SUGGEST 64
@ -84,7 +84,7 @@ public:
bool maybepointer;
Checker(color_ostream & out);
bool queue_item(const QueueItem & item, const CheckedStructure & cs);
bool queue_item(const QueueItem & item, CheckedStructure cs);
void queue_globals();
bool process_queue();

@ -30,52 +30,50 @@ color_ostream & Checker::fail(int line, const QueueItem & item, const CheckedStr
return out;
}
bool Checker::queue_item(const QueueItem & item, const CheckedStructure & cs)
bool Checker::queue_item(const QueueItem & item, CheckedStructure cs)
{
if (data.count(item.ptr))
if (!cs.identity)
{
// already checked
auto existing = data.at(item.ptr);
if (cs.identity != existing.second.identity)
UNEXPECTED;
return false;
}
if (cs.identity->type() == IDTYPE_CLASS)
{
if (cs.identity->type() == IDTYPE_CLASS && existing.second.identity->type() == IDTYPE_CLASS && get_vtable_name(item, cs, false) && static_cast<virtual_identity *>(cs.identity)->is_instance(static_cast<virtual_ptr>(const_cast<void *>(item.ptr))))
if (cs.count)
{
return false;
UNEXPECTED;
}
FAIL("TODO: handle merging structures: " << data.at(item.ptr).first << " overlaps " << item.path << " (same pointer)");
if (get_vtable_name(item, cs, true))
{
auto actual_identity = virtual_identity::get(reinterpret_cast<virtual_ptr>(const_cast<void *>(item.ptr)));
if (static_cast<virtual_identity *>(cs.identity)->is_subclass(actual_identity))
{
cs.identity = actual_identity;
}
}
return false;
}
auto ptr_end = PTR_ADD(item.ptr, cs.full_size());
auto prev = data.lower_bound(item.ptr);
if (prev != data.cbegin())
if (prev != data.cbegin() && uintptr_t(prev->first) > uintptr_t(item.ptr))
{
prev--;
if (uintptr_t(prev->first) + prev->second.second.full_size() > uintptr_t(item.ptr))
{
// placeholder algorithm
if (auto sid = dynamic_cast<struct_identity *>(prev->second.second.identity))
}
if (prev != data.cend() && uintptr_t(prev->first) <= uintptr_t(item.ptr) && uintptr_t(prev->first) + prev->second.second.full_size() > uintptr_t(item.ptr))
{
auto offset = uintptr_t(item.ptr) - uintptr_t(prev->first);
for (auto field = sid->getFields(); field->mode != struct_field_info::END; field++)
{
if (field->offset == offset)
{
if (field->mode == struct_field_info::SUBSTRUCT && field->type == cs.identity)
if (!prev->second.second.has_type_at_offset(cs, offset))
{
// TODO
FAIL("TODO: handle merging structures: " << item.path << " overlaps " << prev->second.first << " (backward)");
return false;
}
UNEXPECTED;
}
}
}
// TODO
FAIL("TODO: handle merging structures: " << prev->second.first << " overlaps " << item.path << " (backward)");
}
// we've already checked this structure, or we're currently queued to do so
return false;
}
auto overlap_start = data.lower_bound(item.ptr);
@ -83,7 +81,7 @@ bool Checker::queue_item(const QueueItem & item, const CheckedStructure & cs)
for (auto overlap = overlap_start; overlap != overlap_end; overlap++)
{
auto offset = uintptr_t(overlap->first) - uintptr_t(item.ptr);
if (!cs.find_field_at_offset_with_type(offset, overlap->second.second))
if (!cs.has_type_at_offset(overlap->second.second, offset))
{
// TODO
FAIL("TODO: handle merging structures: " << overlap->second.first << " overlaps " << item.path << " (forward)");
@ -612,8 +610,60 @@ void Checker::dispatch_tagged_union(const QueueItem & item, const QueueItem & ta
return;
}
auto union_type = static_cast<union_identity *>(cs.identity);
auto union_data_ptr = reinterpret_cast<const uint8_t *>(item.ptr);
uint8_t padding_byte = *union_data_ptr;
bool all_padding = false;
if (padding_byte == 0x00 || padding_byte == 0xd2 || padding_byte == 0xff)
{
all_padding = true;
for (size_t i = 0; i < union_type->byte_size(); i++)
{
if (union_data_ptr[i] != padding_byte)
{
all_padding = false;
break;
}
}
}
auto tag_identity = static_cast<enum_identity *>(tag_cs.identity);
auto tag_value = get_int_value(tag_item, tag_identity->getBaseType());
if (all_padding && padding_byte == 0xd2)
{
// special case: completely uninitialized
switch (tag_identity->byte_size())
{
case 1:
if (tag_value == 0xd2)
{
return;
}
break;
case 2:
if (tag_value == 0xd2d2)
{
return;
}
break;
case 4:
if (tag_value == 0xd2d2d2d2)
{
return;
}
break;
case 8:
if (uint64_t(tag_value) == 0xd2d2d2d2d2d2d2d2)
{
return;
}
break;
default:
UNEXPECTED;
break;
}
}
auto tag_name = get_enum_item_key(tag_identity, tag_value);
if (!tag_name)
{
@ -627,7 +677,6 @@ void Checker::dispatch_tagged_union(const QueueItem & item, const QueueItem & ta
return;
}
auto union_type = static_cast<union_identity *>(cs.identity);
for (auto field = union_type->getFields(); field->mode != struct_field_info::END; field++)
{
if (strcmp(field->name, *tag_name))
@ -644,26 +693,11 @@ void Checker::dispatch_tagged_union(const QueueItem & item, const QueueItem & ta
return;
}
auto union_data_ptr = reinterpret_cast<const uint8_t *>(item.ptr);
uint8_t padding_byte = *union_data_ptr;
if (padding_byte == 0x00 || padding_byte == 0xd2 || padding_byte == 0xff)
{
bool all_padding = true;
for (size_t i = 0; i < union_type->byte_size(); i++)
{
if (union_data_ptr[i] != padding_byte)
{
all_padding = false;
break;
}
}
// don't ask for fields if it's all padding
if (all_padding)
{
return;
}
}
FAIL("tagged union missing " << *tag_name << " field to match tag (accessed as " << tag_item.path << ") value (" << tag_value << ")");
}

@ -107,21 +107,30 @@ size_t CheckedStructure::full_size() const
return size;
}
const struct_field_info *CheckedStructure::find_field_at_offset_with_type(size_t offset, const CheckedStructure & type) const
bool CheckedStructure::has_type_at_offset(const CheckedStructure & type, size_t offset) const
{
if (!identity)
return nullptr;
return false;
if (offset == 0 && identity == type.identity)
return true;
if (offset >= identity->byte_size() && offset < full_size())
offset %= identity->byte_size();
else if (offset >= identity->byte_size())
return nullptr;
return false;
if (identity->type() == IDTYPE_BUFFER)
{
auto target = static_cast<container_identity *>(identity)->getItemType();
return CheckedStructure(target, 0).has_type_at_offset(type, offset % target->byte_size());
}
auto st = dynamic_cast<struct_identity *>(identity);
if (!st)
{
UNEXPECTED;
return nullptr;
return false;
}
for (auto p = st; p; p = p->getParent())
@ -132,18 +141,18 @@ const struct_field_info *CheckedStructure::find_field_at_offset_with_type(size_t
for (auto field = fields; field->mode != struct_field_info::END; field++)
{
if (field->offset > offset)
if (field->mode == struct_field_info::OBJ_METHOD || field->mode == struct_field_info::CLASS_METHOD)
continue;
if (field->offset == offset && CheckedStructure(field).identity == type.identity)
return field;
if (field->offset > offset)
continue;
if (auto subfield = CheckedStructure(field).find_field_at_offset_with_type(offset - field->offset, type))
return subfield;
if (CheckedStructure(field).has_type_at_offset(type, offset - field->offset))
return true;
}
}
return nullptr;
return false;
}
type_identity *Checker::wrap_in_stl_ptr_vector(type_identity *base)