191 lines
5.2 KiB
C++
191 lines
5.2 KiB
C++
#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<char>::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<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 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<type_identity *, std::unique_ptr<df::stl_ptr_vector_identity>> wrappers;
|
|
auto it = wrappers.find(base);
|
|
if (it != wrappers.end())
|
|
{
|
|
return it->second.get();
|
|
}
|
|
return (wrappers[base] = dts::make_unique<df::stl_ptr_vector_identity>(base, nullptr)).get();
|
|
}
|
|
|
|
type_identity *Checker::wrap_in_pointer(type_identity *base)
|
|
{
|
|
static std::map<type_identity *, std::unique_ptr<df::pointer_identity>> wrappers;
|
|
auto it = wrappers.find(base);
|
|
if (it != wrappers.end())
|
|
{
|
|
return it->second.get();
|
|
}
|
|
return (wrappers[base] = dts::make_unique<df::pointer_identity>(base)).get();
|
|
}
|
|
|
|
std::map<size_t, std::vector<std::string>> 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());
|
|
}
|
|
}
|
|
}
|