#include "check-structures-sanity.h" QueueItem::QueueItem(const std::string & path, const void *ptr) : path(path), ptr(ptr) { } QueueItem::QueueItem(const QueueItem & parent, const std::string & member, const void *ptr) : QueueItem(parent.path + "." + member, ptr) { } QueueItem::QueueItem(const QueueItem & parent, size_t index, const void *ptr) : QueueItem(parent.path + stl_sprintf("[%zu]", index), ptr) { } CheckedStructure::CheckedStructure() : CheckedStructure(nullptr, 0) { } CheckedStructure::CheckedStructure(type_identity *identity, size_t count) : CheckedStructure(identity, count, nullptr, false) { } CheckedStructure::CheckedStructure(type_identity *identity, size_t count, enum_identity *eid, bool inside_structure) : identity(identity), count(count), allocated_count(0), eid(eid), ptr_is_array(false), inside_structure(inside_structure) { } CheckedStructure::CheckedStructure(const struct_field_info *field) : CheckedStructure() { if (!field || field->mode == struct_field_info::END) { UNEXPECTED; } identity = field->type; eid = field->extra ? field->extra->index_enum : nullptr; inside_structure = true; switch (field->mode) { case struct_field_info::END: UNEXPECTED; break; case struct_field_info::PRIMITIVE: if (field->count || !field->type) { UNEXPECTED; } break; case struct_field_info::STATIC_STRING: if (!field->count || field->type) { UNEXPECTED; } identity = df::identity_traits::get(); count = field->count; break; case struct_field_info::POINTER: if (field->count & PTRFLAG_IS_ARRAY) { ptr_is_array = true; } identity = Checker::wrap_in_pointer(field->type); break; case struct_field_info::STATIC_ARRAY: if (!field->count || !field->type) { UNEXPECTED; } count = field->count; break; case struct_field_info::SUBSTRUCT: case struct_field_info::CONTAINER: if (field->count || !field->type) { UNEXPECTED; } break; case struct_field_info::STL_VECTOR_PTR: if (field->count) { UNEXPECTED; } identity = Checker::wrap_in_stl_ptr_vector(field->type); break; case struct_field_info::OBJ_METHOD: case struct_field_info::CLASS_METHOD: UNEXPECTED; break; } } size_t CheckedStructure::full_size() const { size_t size = identity->byte_size(); if (count) { size *= count; } return size; } bool CheckedStructure::has_type_at_offset(const CheckedStructure & type, size_t offset) const { if (!identity) 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 false; if (identity->type() == IDTYPE_BUFFER) { auto target = static_cast(identity)->getItemType(); return CheckedStructure(target, 0).has_type_at_offset(type, offset % target->byte_size()); } auto st = dynamic_cast(identity); if (!st) { return false; } for (auto p = st; p; p = p->getParent()) { auto fields = p->getFields(); if (!fields) continue; for (auto field = fields; field->mode != struct_field_info::END; field++) { if (field->mode == struct_field_info::OBJ_METHOD || field->mode == struct_field_info::CLASS_METHOD) continue; if (field->offset > offset) continue; if (CheckedStructure(field).has_type_at_offset(type, offset - field->offset)) return true; } } return false; } type_identity *Checker::wrap_in_stl_ptr_vector(type_identity *base) { static std::map> wrappers; auto it = wrappers.find(base); if (it != wrappers.end()) { return it->second.get(); } return (wrappers[base] = std::make_unique(base, nullptr)).get(); } type_identity *Checker::wrap_in_pointer(type_identity *base) { static std::map> wrappers; auto it = wrappers.find(base); if (it != wrappers.end()) { return it->second.get(); } return (wrappers[base] = std::make_unique(base)).get(); } std::map> known_types_by_size; void build_size_table() { for (auto & ident : compound_identity::getTopScope()) { if (ident->byte_size() >= MIN_SIZE_FOR_SUGGEST) { known_types_by_size[ident->byte_size()].push_back(ident->getFullName()); } } }