diff --git a/plugins/devel/check-structures-sanity/check-structures-sanity.h b/plugins/devel/check-structures-sanity/check-structures-sanity.h index 7db57a6c6..8a68d39e4 100644 --- a/plugins/devel/check-structures-sanity/check-structures-sanity.h +++ b/plugins/devel/check-structures-sanity/check-structures-sanity.h @@ -44,6 +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; }; #define MIN_SIZE_FOR_SUGGEST 64 @@ -87,6 +88,7 @@ public: void queue_globals(); bool process_queue(); + bool is_in_global(const QueueItem & item); bool is_valid_dereference(const QueueItem & item, const CheckedStructure & cs, size_t size, bool quiet); inline bool is_valid_dereference(const QueueItem & item, const CheckedStructure & cs, bool quiet = false) { diff --git a/plugins/devel/check-structures-sanity/dispatch.cpp b/plugins/devel/check-structures-sanity/dispatch.cpp index 77b16e39e..c2b7beada 100644 --- a/plugins/devel/check-structures-sanity/dispatch.cpp +++ b/plugins/devel/check-structures-sanity/dispatch.cpp @@ -78,15 +78,21 @@ bool Checker::queue_item(const QueueItem & item, const CheckedStructure & cs) } } - auto overlap = data.lower_bound(item.ptr); + auto overlap_start = data.lower_bound(item.ptr); auto overlap_end = data.lower_bound(ptr_end); - while (overlap != overlap_end) + for (auto overlap = overlap_start; overlap != overlap_end; overlap++) { - // TODO - FAIL("TODO: handle merging structures: " << overlap->second.first << " overlaps " << item.path << " (forward)"); - overlap++; + auto offset = uintptr_t(overlap->first) - uintptr_t(item.ptr); + if (!cs.find_field_at_offset_with_type(offset, overlap->second.second)) + { + // TODO + FAIL("TODO: handle merging structures: " << overlap->second.first << " overlaps " << item.path << " (forward)"); + return false; + } } + data.erase(overlap_start, overlap_end); + data[item.ptr] = std::make_pair(item.path, cs); queue.push_back(item); return true; @@ -326,7 +332,7 @@ void Checker::dispatch_pointer(const QueueItem & item, const CheckedStructure & auto target = static_cast(cs.identity)->getTarget(); if (!target) { - check_unknown_pointer(item); + check_unknown_pointer(target_item); return; } @@ -362,6 +368,10 @@ void Checker::dispatch_container(const QueueItem & item, const CheckedStructure { // TODO: check deque? } + else if (base_container == "DfArray") + { + // TODO: check DfArray + } else { UNEXPECTED; @@ -486,6 +496,11 @@ void Checker::dispatch_enum(const QueueItem & item, const CheckedStructure & cs) return; } + if (is_in_global(item) && enum_value == 0) + { + return; + } + auto enum_name = get_enum_item_key(enum_type, enum_value); if (!enum_name) { diff --git a/plugins/devel/check-structures-sanity/types.cpp b/plugins/devel/check-structures-sanity/types.cpp index 4c4529706..4f5e8ca3a 100644 --- a/plugins/devel/check-structures-sanity/types.cpp +++ b/plugins/devel/check-structures-sanity/types.cpp @@ -107,6 +107,45 @@ 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 +{ + if (!identity) + return nullptr; + + if (offset >= identity->byte_size() && offset < full_size()) + offset %= identity->byte_size(); + else if (offset >= identity->byte_size()) + return nullptr; + + auto st = dynamic_cast(identity); + if (!st) + { + UNEXPECTED; + return nullptr; + } + + 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->offset > offset) + continue; + + if (field->offset == offset && CheckedStructure(field).identity == type.identity) + return field; + + if (auto subfield = CheckedStructure(field).find_field_at_offset_with_type(offset - field->offset, type)) + return subfield; + } + } + + return nullptr; +} + type_identity *Checker::wrap_in_stl_ptr_vector(type_identity *base) { static std::map> wrappers; diff --git a/plugins/devel/check-structures-sanity/validate.cpp b/plugins/devel/check-structures-sanity/validate.cpp index cdf0fe64e..a3ed03980 100644 --- a/plugins/devel/check-structures-sanity/validate.cpp +++ b/plugins/devel/check-structures-sanity/validate.cpp @@ -1,5 +1,21 @@ #include "check-structures-sanity.h" +bool Checker::is_in_global(const QueueItem & item) +{ + auto fields = df::global::_identity.getFields(); + for (auto field = fields; field->mode != struct_field_info::END; field++) + { + size_t size = CheckedStructure(field).full_size(); + auto start = *reinterpret_cast(field->offset); + auto offset = uintptr_t(item.ptr) - uintptr_t(start); + if (offset < size) + { + return true; + } + } + + return false; +} bool Checker::is_valid_dereference(const QueueItem & item, const CheckedStructure & cs, size_t size, bool quiet) { auto base = const_cast(item.ptr);