change DF version

add -maxerrors and -failfast to check-structures-sanity
develop
Ben Lubar 2020-03-01 12:15:26 -06:00
parent 102fedc2ff
commit fe2ea17880
No known key found for this signature in database
GPG Key ID: 92939677AB59EDA4
2 changed files with 73 additions and 58 deletions

@ -173,8 +173,8 @@ if(NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhack
endif() endif()
# set up versioning. # set up versioning.
set(DF_VERSION "0.47.03") set(DF_VERSION "0.47.04")
set(DFHACK_RELEASE "beta1") set(DFHACK_RELEASE "alpha0")
set(DFHACK_PRERELEASE TRUE) set(DFHACK_PRERELEASE TRUE)
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")

@ -40,11 +40,13 @@ DFhackCExport command_result plugin_init(color_ostream &, std::vector<PluginComm
"performs a sanity check on df-structures", "performs a sanity check on df-structures",
command, command,
false, false,
"check-structures-sanity [-enums] [-sizes] [-lowmem] [starting_point]\n" "check-structures-sanity [-enums] [-sizes] [-lowmem] [-maxerrors n] [-failfast] [starting_point]\n"
"\n" "\n"
"-enums: report unexpected or unnamed enum or bitfield values.\n" "-enums: report unexpected or unnamed enum or bitfield values.\n"
"-sizes: report struct and class sizes that don't match structures. (requires sizecheck)\n" "-sizes: report struct and class sizes that don't match structures. (requires sizecheck)\n"
"-lowmem: use depth-first search instead of breadth-first search. uses less memory but may produce less sensible field names.\n" "-lowmem: use depth-first search instead of breadth-first search. uses less memory but processes fields in a less intuitive order.\n"
"-maxerrors n: set the maximum number of errors before bailing out.\n"
"-failfast: crash if any error is encountered. useful only for debugging.\n"
"starting_point: a lua expression or a word like 'screen', 'item', or 'building'. (defaults to df.global)\n" "starting_point: a lua expression or a word like 'screen', 'item', or 'building'. (defaults to df.global)\n"
"\n" "\n"
"by default, check-structures-sanity reports invalid pointers, vectors, strings, and vtables." "by default, check-structures-sanity reports invalid pointers, vectors, strings, and vtables."
@ -76,45 +78,46 @@ static const char *const *get_enum_item_key(enum_identity *identity, int64_t val
return &identity->getKeys()[index]; return &identity->getKeys()[index];
} }
static const struct_field_info *find_union_tag(const struct_field_info *fields, const struct_field_info *union_field) static const struct_field_info *find_union_tag_field(const struct_field_info *fields, const struct_field_info *union_field)
{ {
if (union_field->mode != struct_field_info::SUBSTRUCT ||
!union_field->type ||
union_field->type->type() != IDTYPE_UNION)
{
// not a union
return nullptr;
}
const struct_field_info *tag_field = union_field + 1;
std::string name(union_field->name); std::string name(union_field->name);
if (name.length() >= 4 && name.substr(name.length() - 4) == "data") if (name.length() >= 4 && name.substr(name.length() - 4) == "data")
{ {
name.erase(name.length() - 4, 4); name.erase(name.length() - 4, 4);
name += "type"; name += "type";
if (tag_field->mode != struct_field_info::END && tag_field->name == name) for (auto field = fields; field->mode != struct_field_info::END; field++)
{
// fast path; we already have the correct field
}
else
{ {
for (auto field = fields; field->mode != struct_field_info::END; field++) if (field->name == name)
{ {
if (field->name == name) return field;
{
tag_field = field;
break;
}
} }
} }
} }
else if (name.length() > 7 && name.substr(name.length() - 7) == "_target" && fields != union_field && (union_field - 1)->name == name.substr(0, name.length() - 7))
if (name.length() > 7 &&
name.substr(name.length() - 7) == "_target" &&
fields != union_field &&
(union_field - 1)->name == name.substr(0, name.length() - 7))
{
return union_field - 1;
}
return union_field + 1;
}
static const struct_field_info *find_union_tag(const struct_field_info *fields, const struct_field_info *union_field)
{
if (union_field->mode != struct_field_info::SUBSTRUCT ||
!union_field->type ||
union_field->type->type() != IDTYPE_UNION)
{ {
tag_field = union_field - 1; // not a union
return nullptr;
} }
const struct_field_info *tag_field = find_union_tag_field(fields, union_field);
if (tag_field->mode != struct_field_info::PRIMITIVE || if (tag_field->mode != struct_field_info::PRIMITIVE ||
!tag_field->type || !tag_field->type ||
tag_field->type->type() != IDTYPE_ENUM) tag_field->type->type() != IDTYPE_ENUM)
@ -145,35 +148,7 @@ static const struct_field_info *find_union_vector_tag_vector(const struct_field_
return nullptr; return nullptr;
} }
const struct_field_info *tag_field = union_field + 1; const struct_field_info *tag_field = find_union_tag_field(fields, union_field);
std::string name(union_field->name);
if (name.length() >= 4 && name.substr(name.length() - 4) == "data")
{
name.erase(name.length() - 4, 4);
name += "type";
if (tag_field->mode != struct_field_info::END && tag_field->name == name)
{
// fast path; we already have the correct field
}
else
{
for (auto field = fields; field->mode != struct_field_info::END; field++)
{
if (field->name == name)
{
tag_field = field;
break;
}
}
}
}
else if (name.length() > 7 && name.substr(name.length() - 7) == "_target" && fields != union_field && (union_field - 1)->name == name.substr(0, name.length() - 7))
{
tag_field = union_field - 1;
}
if (tag_field->mode != struct_field_info::CONTAINER || if (tag_field->mode != struct_field_info::CONTAINER ||
!tag_field->type || !tag_field->type ||
tag_field->type->type() != IDTYPE_CONTAINER) tag_field->type->type() != IDTYPE_CONTAINER)
@ -230,6 +205,8 @@ public:
bool enums; bool enums;
bool sizes; bool sizes;
bool lowmem; bool lowmem;
bool failfast;
size_t maxerrors;
private: private:
bool ok; bool ok;
@ -272,9 +249,34 @@ static command_result command(color_ostream & out, std::vector<std::string> & pa
Checker checker(out); Checker checker(out);
// check parameters with values first
#define VAL_PARAM(name, expr_using_value) \
auto name ## _idx = std::find(parameters.begin(), parameters.end(), "-" #name); \
if (name ## _idx != parameters.end()) \
{ \
if (name ## _idx + 1 == parameters.end()) \
{ \
return CR_WRONG_USAGE; \
} \
try \
{ \
auto value = std::move(*(name ## _idx + 1)); \
parameters.erase((name ## _idx + 1)); \
parameters.erase(name ## _idx); \
checker.name = (expr_using_value); \
} \
catch (std::exception & ex) \
{ \
out.printerr("check-structures-sanity: argument to -%s: %s\n", #name, ex.what()); \
return CR_WRONG_USAGE; \
} \
}
VAL_PARAM(maxerrors, std::stoul(value));
#undef VAL_PARAM
#define BOOL_PARAM(name) \ #define BOOL_PARAM(name) \
auto name ## _idx = std::find(parameters.begin(), parameters.end(), "-" #name); \ auto name ## _idx = std::find(parameters.begin(), parameters.end(), "-" #name); \
if (name ## _idx != parameters.cend()) \ if (name ## _idx != parameters.end()) \
{ \ { \
checker.name = true; \ checker.name = true; \
parameters.erase(name ## _idx); \ parameters.erase(name ## _idx); \
@ -282,6 +284,7 @@ static command_result command(color_ostream & out, std::vector<std::string> & pa
BOOL_PARAM(enums); BOOL_PARAM(enums);
BOOL_PARAM(sizes); BOOL_PARAM(sizes);
BOOL_PARAM(lowmem); BOOL_PARAM(lowmem);
BOOL_PARAM(failfast);
#undef BOOL_PARAM #undef BOOL_PARAM
if (parameters.size() > 1) if (parameters.size() > 1)
@ -342,6 +345,8 @@ Checker::Checker(color_ostream & out) :
enums = false; enums = false;
sizes = false; sizes = false;
lowmem = false; lowmem = false;
failfast = false;
maxerrors = ~size_t(0);
} }
bool Checker::check() bool Checker::check()
@ -352,6 +357,12 @@ bool Checker::check()
while (!queue.empty()) while (!queue.empty())
{ {
if (!maxerrors)
{
out << "hit max error count. bailing out with " << queue.size() << " fields in queue." << std::endl;
break;
}
ToCheck current; ToCheck current;
if (lowmem) if (lowmem)
{ {
@ -388,6 +399,10 @@ bool Checker::check()
out << "): "; \ out << "): "; \
out << COLOR_YELLOW << message; \ out << COLOR_YELLOW << message; \
out << COLOR_RESET << std::endl; \ out << COLOR_RESET << std::endl; \
if (maxerrors && maxerrors != ~size_t(0)) \
maxerrors--; \
if (failfast) \
UNEXPECTED; \
} while (false) } while (false)
#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))))