allow tagged unions to not be union followed by tag

develop
Ben Lubar 2020-02-23 21:33:32 -06:00
parent 1e3e3829a7
commit e9564a28f5
No known key found for this signature in database
GPG Key ID: 92939677AB59EDA4
2 changed files with 33 additions and 53 deletions

@ -1 +1 @@
Subproject commit 7048df4a22fe59cab941a41dd8c6d0f4830f77b3 Subproject commit ed8fc292e8236c589b40b064bc5ab63f23cb9b36

@ -88,7 +88,6 @@ public:
private: private:
bool ok; bool ok;
bool address_in_runtime_data(const void *);
#ifndef WIN32 #ifndef WIN32
// this function doesn't make sense on windows, where std::string is not pointer-sized. // this function doesn't make sense on windows, where std::string is not pointer-sized.
const std::string *check_possible_stl_string_pointer(const void *const*); const std::string *check_possible_stl_string_pointer(const void *const*);
@ -98,7 +97,7 @@ private:
bool check_vtable(const ToCheck &, void *, type_identity *); bool check_vtable(const ToCheck &, void *, type_identity *);
void queue_field(ToCheck &&, const struct_field_info *); void queue_field(ToCheck &&, const struct_field_info *);
void queue_static_array(const ToCheck &, void *, type_identity *, size_t, bool = false, enum_identity * = nullptr); void queue_static_array(const ToCheck &, void *, type_identity *, size_t, bool = false, enum_identity * = nullptr);
bool maybe_queue_tagged_union(const ToCheck &, const struct_field_info *); bool maybe_queue_tagged_union(const ToCheck &, const struct_field_info *, const struct_field_info *);
void check_dispatch(const ToCheck &); void check_dispatch(const ToCheck &);
void check_global(const ToCheck &); void check_global(const ToCheck &);
void check_primitive(const ToCheck &); void check_primitive(const ToCheck &);
@ -245,40 +244,14 @@ bool Checker::check()
#define PTR_ADD(base, offset) (reinterpret_cast<void *>(reinterpret_cast<uintptr_t>((base)) + static_cast<ptrdiff_t>((offset)))) #define PTR_ADD(base, offset) (reinterpret_cast<void *>(reinterpret_cast<uintptr_t>((base)) + static_cast<ptrdiff_t>((offset))))
bool Checker::address_in_runtime_data(const void *ptr)
{
for (auto & range : mapped)
{
if (!range.isInRange(const_cast<void *>(ptr)))
{
continue;
}
#ifdef WIN32
// TODO: figure out how to differentiate statically-allocated pages
// from malloc'd data pages
UNEXPECTED;
return false;
#else
return !strcmp(range.name, "[heap]");
#endif
}
return false;
}
#ifndef WIN32 #ifndef WIN32
const std::string *Checker::check_possible_stl_string_pointer(const void *const*base) const std::string *Checker::check_possible_stl_string_pointer(const void *const*base)
{ {
#ifdef DFHACK64
// on 64-bit linux, empty string is statically allocated.
// on 32-bit linux, empty string is heap-allocated.
std::string empty_string; std::string empty_string;
if (*base == *reinterpret_cast<void **>(&empty_string)) if (*base == *reinterpret_cast<void **>(&empty_string))
{ {
return reinterpret_cast<const std::string *>(base); return reinterpret_cast<const std::string *>(base);
} }
#endif
const struct string_data_inner const struct string_data_inner
{ {
@ -287,9 +260,6 @@ const std::string *Checker::check_possible_stl_string_pointer(const void *const*
int32_t refcount; int32_t refcount;
} *str_data = static_cast<const string_data_inner *>(*base) - 1; } *str_data = static_cast<const string_data_inner *>(*base) - 1;
bool heap_allocated = address_in_runtime_data(*base);
if (heap_allocated)
{
uint32_t tag = *reinterpret_cast<const uint32_t *>(PTR_ADD(str_data, -8)); uint32_t tag = *reinterpret_cast<const uint32_t *>(PTR_ADD(str_data, -8));
if (tag == 0xdfdf4ac8) if (tag == 0xdfdf4ac8)
{ {
@ -305,11 +275,6 @@ const std::string *Checker::check_possible_stl_string_pointer(const void *const*
{ {
return nullptr; return nullptr;
} }
}
else if (!str_data->length)
{
return nullptr;
}
if (str_data->capacity < str_data->length) if (str_data->capacity < str_data->length)
{ {
@ -554,9 +519,29 @@ void Checker::queue_static_array(const ToCheck & array, void *base, type_identit
} }
} }
bool Checker::maybe_queue_tagged_union(const ToCheck & item, const struct_field_info *field) bool Checker::maybe_queue_tagged_union(const ToCheck & item, const struct_field_info *field, const struct_field_info *fields)
{ {
const struct_field_info *tag_field = field + 1; const struct_field_info *tag_field = field + 1;
std::string name = field->name;
if (name.length() >= 4 && name.substr(name.length() - 4) == "data")
{
name.erase(name.length() - 4, 4);
name += "type";
if (tag_field->name != name)
{
for (auto f = fields; f->mode != struct_field_info::END; f++)
{
if (f->name == name)
{
tag_field = f;
break;
}
}
}
}
if (field->mode != struct_field_info::SUBSTRUCT || tag_field->mode != struct_field_info::PRIMITIVE) if (field->mode != struct_field_info::SUBSTRUCT || tag_field->mode != struct_field_info::PRIMITIVE)
{ {
return false; return false;
@ -666,13 +651,9 @@ void Checker::check_dispatch(const ToCheck & item)
FAIL("untyped pointer is actually stl-string with value \"" << *str << "\" (length " << str->length() << ")"); FAIL("untyped pointer is actually stl-string with value \"" << *str << "\" (length " << str->length() << ")");
} }
#endif #endif
else if (address_in_runtime_data(item.ptr))
{
FAIL("pointer to heap memory, but no size information (part of some STL type?)");
}
else else
{ {
FAIL("pointer to non-heap memory (probably incorrect)"); FAIL("pointer to memory with no size information");
} }
} }
@ -868,7 +849,7 @@ void Checker::check_stl_string(const ToCheck & item)
FAIL("allocated string data size (" << allocated_size << ") does not match expected size (" << expected_size << ")"); FAIL("allocated string data size (" << allocated_size << ") does not match expected size (" << expected_size << ")");
} }
} }
else if (address_in_runtime_data(string->ptr)) else
{ {
UNEXPECTED; UNEXPECTED;
} }
@ -1194,7 +1175,7 @@ void Checker::check_struct(const ToCheck & item)
FAIL("allocated structure size (" << allocated_size << ") does not match expected size (" << expected_size << ")"); FAIL("allocated structure size (" << allocated_size << ") does not match expected size (" << expected_size << ")");
} }
} }
else if (address_in_runtime_data(item.ptr)) else
{ {
UNEXPECTED; UNEXPECTED;
} }
@ -1210,9 +1191,8 @@ void Checker::check_struct(const ToCheck & item)
for (auto field = fields; field->mode != struct_field_info::END; field++) for (auto field = fields; field->mode != struct_field_info::END; field++)
{ {
if (maybe_queue_tagged_union(item, field)) if (maybe_queue_tagged_union(item, field, fields))
{ {
field++;
continue; continue;
} }