From fe2ea1788024ab88f9deee1bff1e04114f87cf61 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Sun, 1 Mar 2020 12:15:26 -0600 Subject: [PATCH 01/15] change DF version add -maxerrors and -failfast to check-structures-sanity --- CMakeLists.txt | 4 +- plugins/devel/check-structures-sanity.cpp | 127 ++++++++++++---------- 2 files changed, 73 insertions(+), 58 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 58bce6dc3..a5a1b2579 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,8 +173,8 @@ if(NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhack endif() # set up versioning. -set(DF_VERSION "0.47.03") -set(DFHACK_RELEASE "beta1") +set(DF_VERSION "0.47.04") +set(DFHACK_RELEASE "alpha0") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/plugins/devel/check-structures-sanity.cpp b/plugins/devel/check-structures-sanity.cpp index 6b439692f..68a26ba30 100644 --- a/plugins/devel/check-structures-sanity.cpp +++ b/plugins/devel/check-structures-sanity.cpp @@ -40,11 +40,13 @@ DFhackCExport command_result plugin_init(color_ostream &, std::vectorgetKeys()[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); 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++) { - for (auto field = fields; field->mode != struct_field_info::END; field++) + if (field->name == name) { - if (field->name == name) - { - tag_field = field; - break; - } + return field; } } } - 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 || !tag_field->type || 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; } - const struct_field_info *tag_field = union_field + 1; - - 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; - } - + const struct_field_info *tag_field = find_union_tag_field(fields, union_field); if (tag_field->mode != struct_field_info::CONTAINER || !tag_field->type || tag_field->type->type() != IDTYPE_CONTAINER) @@ -230,6 +205,8 @@ public: bool enums; bool sizes; bool lowmem; + bool failfast; + size_t maxerrors; private: bool ok; @@ -272,9 +249,34 @@ static command_result command(color_ostream & out, std::vector & pa 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) \ auto name ## _idx = std::find(parameters.begin(), parameters.end(), "-" #name); \ - if (name ## _idx != parameters.cend()) \ + if (name ## _idx != parameters.end()) \ { \ checker.name = true; \ parameters.erase(name ## _idx); \ @@ -282,6 +284,7 @@ static command_result command(color_ostream & out, std::vector & pa BOOL_PARAM(enums); BOOL_PARAM(sizes); BOOL_PARAM(lowmem); + BOOL_PARAM(failfast); #undef BOOL_PARAM if (parameters.size() > 1) @@ -342,6 +345,8 @@ Checker::Checker(color_ostream & out) : enums = false; sizes = false; lowmem = false; + failfast = false; + maxerrors = ~size_t(0); } bool Checker::check() @@ -352,6 +357,12 @@ bool Checker::check() while (!queue.empty()) { + if (!maxerrors) + { + out << "hit max error count. bailing out with " << queue.size() << " fields in queue." << std::endl; + break; + } + ToCheck current; if (lowmem) { @@ -388,6 +399,10 @@ bool Checker::check() out << "): "; \ out << COLOR_YELLOW << message; \ out << COLOR_RESET << std::endl; \ + if (maxerrors && maxerrors != ~size_t(0)) \ + maxerrors--; \ + if (failfast) \ + UNEXPECTED; \ } while (false) #define PTR_ADD(base, offset) (reinterpret_cast(reinterpret_cast((base)) + static_cast((offset)))) From 00244571678d5335b5d6f9a7d33887e60d07907e Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 2 Mar 2020 02:27:15 -0600 Subject: [PATCH 02/15] update structures don't mark lua argument as a pointer (to be revisited at some point) --- library/xml | 2 +- plugins/devel/check-structures-sanity.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 212e3b4d6..24ed65035 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 212e3b4d69b65c260a034522429c0b39c8f09bc0 +Subproject commit 24ed650356467b48ee12db9b22deb0528430d375 diff --git a/plugins/devel/check-structures-sanity.cpp b/plugins/devel/check-structures-sanity.cpp index 68a26ba30..e41c3948c 100644 --- a/plugins/devel/check-structures-sanity.cpp +++ b/plugins/devel/check-structures-sanity.cpp @@ -321,7 +321,6 @@ static command_result command(color_ostream & out, std::vector & pa ToCheck ref; ref.path.push_back(parameters.at(0)); - ref.path.push_back(""); // tell check_struct that it is a pointer ref.ptr = get_object_ref(State, -1); lua_getfield(State, -1, "_type"); lua_getfield(State, -1, "_identity"); From 269b3cb8ebb30a42d11e3fc6aa9669afc7c4c972 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 2 Mar 2020 15:34:29 -0600 Subject: [PATCH 03/15] add support for finding vtable pointers to check-structures-sanity update structures --- library/xml | 2 +- plugins/devel/check-structures-sanity.cpp | 24 +++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/library/xml b/library/xml index 24ed65035..9df961c03 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 24ed650356467b48ee12db9b22deb0528430d375 +Subproject commit 9df961c0382cfdf052dfac2315c39a7260c497c5 diff --git a/plugins/devel/check-structures-sanity.cpp b/plugins/devel/check-structures-sanity.cpp index e41c3948c..6c9f5fb49 100644 --- a/plugins/devel/check-structures-sanity.cpp +++ b/plugins/devel/check-structures-sanity.cpp @@ -216,7 +216,7 @@ private: #endif bool check_access(const ToCheck &, void *, type_identity *); bool check_access(const ToCheck &, void *, type_identity *, size_t); - bool check_vtable(const ToCheck &, void *, type_identity *); + const char *check_vtable(const ToCheck &, void *, type_identity *); void queue_field(ToCheck &&, const struct_field_info *); void queue_static_array(const ToCheck &, void *, type_identity *, size_t, bool = false, enum_identity * = nullptr); bool maybe_queue_union(const ToCheck &, const struct_field_info *, const struct_field_info *); @@ -535,20 +535,20 @@ bool Checker::check_access(const ToCheck & item, void *base, type_identity *iden #undef FAIL_PTR } -bool Checker::check_vtable(const ToCheck & item, void *vtable, type_identity *identity) +const char *Checker::check_vtable(const ToCheck & item, void *vtable, type_identity *identity) { if (!check_access(item, PTR_ADD(vtable, -ptrdiff_t(sizeof(void *))), identity, sizeof(void *))) - return false; + return nullptr; char **info = *(reinterpret_cast(vtable) - 1); #ifdef WIN32 if (!check_access(item, PTR_ADD(info, 12), identity, 4)) - return false; + return nullptr; #ifdef DFHACK64 void *base; if (!RtlPcToFileHeader(info, &base)) - return false; + return nullptr; char *typeinfo = reinterpret_cast(base) + reinterpret_cast(info)[3]; char *name = typeinfo + 16; @@ -557,7 +557,7 @@ bool Checker::check_vtable(const ToCheck & item, void *vtable, type_identity *id #endif #else if (!check_access(item, info + 1, identity, sizeof(void *))) - return false; + return nullptr; char *name = *(info + 1); #endif @@ -571,7 +571,7 @@ bool Checker::check_vtable(const ToCheck & item, void *vtable, type_identity *id if (!range.valid || !range.read) { FAIL("pointer to invalid memory range"); - return false; + return nullptr; } bool letter = false; @@ -579,7 +579,7 @@ bool Checker::check_vtable(const ToCheck & item, void *vtable, type_identity *id { if (!range.isInRange(p)) { - return false; + return nullptr; } if (*p >= 'a' && *p <= 'z') @@ -588,12 +588,12 @@ bool Checker::check_vtable(const ToCheck & item, void *vtable, type_identity *id } else if (!*p) { - return letter; + return letter ? name : nullptr; } } } - return false; + return nullptr; } void Checker::queue_field(ToCheck && item, const struct_field_info *field) @@ -834,6 +834,10 @@ void Checker::check_dispatch(ToCheck & item) FAIL("untyped pointer is actually stl-string with value \"" << *str << "\" (length " << str->length() << ")"); } #endif + else if (auto vtable_name = check_vtable(item, item.ptr, df::identity_traits::get())) + { + FAIL("pointer to a vtable: " << vtable_name); + } else { FAIL("pointer to memory with no size information"); From 4da0a761ea6c186e34121d7b8d7e76b96ef1012a Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 2 Mar 2020 18:36:28 -0600 Subject: [PATCH 04/15] update structures --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 9df961c03..dc94de37c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9df961c0382cfdf052dfac2315c39a7260c497c5 +Subproject commit dc94de37c459129dd75d79458eb255db5c8fea33 From 66ded03bc1a554b1c642ac343fbf3e533dedd4ab Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 2 Mar 2020 20:41:13 -0600 Subject: [PATCH 05/15] update structures --- library/modules/Units.cpp | 4 ++-- library/xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 1907b1641..3ac235203 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -1001,7 +1001,7 @@ int Units::computeMovementSpeed(df::unit *unit) if (in_magma) speed *= 2; - if (craw->flags.is_set(caste_raw_flags::SWIMS_LEARNED)) + if (craw->flags.is_set(caste_raw_flags::CAN_SWIM)) { int skill = Units::getEffectiveSkill(unit, job_skill::SWIMMING); @@ -1441,7 +1441,7 @@ int8_t Units::getCasteProfessionColor(int race, int casteid, df::profession pid) { if (auto caste = vector_get(creature->caste, casteid)) { - if (caste->flags.is_set(caste_raw_flags::CASTE_COLOR)) + if (caste->flags.is_set(caste_raw_flags::HAS_COLOR)) return caste->caste_color[0] + caste->caste_color[2] * 8; } return creature->color[0] + creature->color[2] * 8; diff --git a/library/xml b/library/xml index dc94de37c..fa22bd5c5 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit dc94de37c459129dd75d79458eb255db5c8fea33 +Subproject commit fa22bd5c5a6ea6ffbd883aea5dfcd2bb18d76dcf From c29b606a4a14070e6cf20c5a7f269ec9f3d4ff3c Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 2 Mar 2020 21:33:04 -0600 Subject: [PATCH 06/15] check-structures-sanity: suggest known structure types for large unknown pointers update structures --- library/xml | 2 +- plugins/devel/check-structures-sanity.cpp | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/library/xml b/library/xml index fa22bd5c5..614548ce6 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit fa22bd5c5a6ea6ffbd883aea5dfcd2bb18d76dcf +Subproject commit 614548ce67ef3d154297167ecacfd9b8c2d49875 diff --git a/plugins/devel/check-structures-sanity.cpp b/plugins/devel/check-structures-sanity.cpp index 6c9f5fb49..a78718cf9 100644 --- a/plugins/devel/check-structures-sanity.cpp +++ b/plugins/devel/check-structures-sanity.cpp @@ -33,6 +33,10 @@ static command_result command(color_ostream &, std::vector &); #define UNEXPECTED __asm__ volatile ("int $0x03") #endif +#define MIN_SIZE_FOR_SUGGEST 64 +static std::map> known_types_by_size; +static void build_size_table(); + DFhackCExport command_result plugin_init(color_ostream &, std::vector & commands) { commands.push_back(PluginCommand( @@ -51,9 +55,24 @@ DFhackCExport command_result plugin_init(color_ostream &, std::vectorbyte_size() >= MIN_SIZE_FOR_SUGGEST) + { + known_types_by_size[ident->byte_size()].push_back(ident->getFullName()); + } + } +} + static const char *const *get_enum_item_key(enum_identity *identity, int64_t value) { size_t index; @@ -827,6 +846,10 @@ void Checker::check_dispatch(ToCheck & item) item.path.push_back(""); item.identity = df::identity_traits::get(); } + else if (allocated_size >= MIN_SIZE_FOR_SUGGEST && known_types_by_size.count(allocated_size)) + { + FAIL("known types of this size: " << join_strings(", ", known_types_by_size.at(allocated_size))); + } } #ifndef WIN32 else if (auto str = check_possible_stl_string_pointer(&item.ptr)) From 7784e569a5dd486ebc1cab1cf8010316461dcde3 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 2 Mar 2020 22:29:53 -0600 Subject: [PATCH 07/15] update structures --- library/xml | 2 +- plugins/fastdwarf.cpp | 34 +++++++++---------- .../remotefortressreader.cpp | 12 +++---- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/library/xml b/library/xml index 614548ce6..5653a57e0 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 614548ce67ef3d154297167ecacfd9b8c2d49875 +Subproject commit 5653a57e0978a78c1f1ef125b63359fefa7660f2 diff --git a/plugins/fastdwarf.cpp b/plugins/fastdwarf.cpp index 09d831e26..975280ea1 100644 --- a/plugins/fastdwarf.cpp +++ b/plugins/fastdwarf.cpp @@ -123,55 +123,55 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) case unit_action_type::None: break; case unit_action_type::Move: - action->data.move.timer = 1; + action->data.Move.timer = 1; break; case unit_action_type::Attack: // Attacks are executed when timer1 reaches zero, which will be // on the following tick. - if (action->data.attack.timer1 > 1) - action->data.attack.timer1 = 1; + if (action->data.Attack.timer1 > 1) + action->data.Attack.timer1 = 1; // Attack actions are completed, and new ones generated, when // timer2 reaches zero. - if (action->data.attack.timer2 > 1) - action->data.attack.timer2 = 1; + if (action->data.Attack.timer2 > 1) + action->data.Attack.timer2 = 1; break; case unit_action_type::HoldTerrain: - action->data.holdterrain.timer = 1; + action->data.HoldTerrain.timer = 1; break; case unit_action_type::Climb: - action->data.climb.timer = 1; + action->data.Climb.timer = 1; break; case unit_action_type::Job: - action->data.job.timer = 1; + action->data.Job.timer = 1; // could also patch the unit->job.current_job->completion_timer break; case unit_action_type::Talk: - action->data.talk.timer = 1; + action->data.Talk.timer = 1; break; case unit_action_type::Unsteady: - action->data.unsteady.timer = 1; + action->data.Unsteady.timer = 1; break; case unit_action_type::Dodge: - action->data.dodge.timer = 1; + action->data.Dodge.timer = 1; break; case unit_action_type::Recover: - action->data.recover.timer = 1; + action->data.Recover.timer = 1; break; case unit_action_type::StandUp: - action->data.standup.timer = 1; + action->data.StandUp.timer = 1; break; case unit_action_type::LieDown: - action->data.liedown.timer = 1; + action->data.LieDown.timer = 1; break; case unit_action_type::Job2: - action->data.job2.timer = 1; + action->data.Job2.timer = 1; // could also patch the unit->job.current_job->completion_timer break; case unit_action_type::PushObject: - action->data.pushobject.timer = 1; + action->data.PushObject.timer = 1; break; case unit_action_type::SuckBlood: - action->data.suckblood.timer = 1; + action->data.SuckBlood.timer = 1; break; case unit_action_type::Jump: case unit_action_type::ReleaseTerrain: diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index f63ae5b2c..aeb242250 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -1825,17 +1825,17 @@ static command_result GetUnitListInside(color_ostream &stream, const BlockReques case unit_action_type::Move: if (unit->path.path.x.size() > 0) { - send_unit->set_subpos_x(lerp(0, unit->path.path.x[0] - unit->pos.x, (float)(action->data.move.timer_init - action->data.move.timer) / action->data.move.timer_init)); - send_unit->set_subpos_y(lerp(0, unit->path.path.y[0] - unit->pos.y, (float)(action->data.move.timer_init - action->data.move.timer) / action->data.move.timer_init)); - send_unit->set_subpos_z(lerp(0, unit->path.path.z[0] - unit->pos.z, (float)(action->data.move.timer_init - action->data.move.timer) / action->data.move.timer_init)); + send_unit->set_subpos_x(lerp(0, unit->path.path.x[0] - unit->pos.x, (float)(action->data.Move.timer_init - action->data.Move.timer) / action->data.Move.timer_init)); + send_unit->set_subpos_y(lerp(0, unit->path.path.y[0] - unit->pos.y, (float)(action->data.Move.timer_init - action->data.Move.timer) / action->data.Move.timer_init)); + send_unit->set_subpos_z(lerp(0, unit->path.path.z[0] - unit->pos.z, (float)(action->data.Move.timer_init - action->data.Move.timer) / action->data.Move.timer_init)); } break; case unit_action_type::Job: { auto facing = send_unit->mutable_facing(); - facing->set_x(action->data.job.x - unit->pos.x); - facing->set_y(action->data.job.y - unit->pos.y); - facing->set_z(action->data.job.z - unit->pos.z); + facing->set_x(action->data.Job.x - unit->pos.x); + facing->set_y(action->data.Job.y - unit->pos.y); + facing->set_z(action->data.Job.z - unit->pos.z); } default: break; From e5c597f8692f935a2f000febed13525418d2b028 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 2 Mar 2020 22:30:23 -0600 Subject: [PATCH 08/15] change two UNEXPECTEDs in check-structures-sanity to FAILs instead --- plugins/devel/check-structures-sanity.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/devel/check-structures-sanity.cpp b/plugins/devel/check-structures-sanity.cpp index a78718cf9..1d832aaac 100644 --- a/plugins/devel/check-structures-sanity.cpp +++ b/plugins/devel/check-structures-sanity.cpp @@ -1076,7 +1076,8 @@ void Checker::check_stl_string(const ToCheck & item) } else { - UNEXPECTED; + FAIL("pointer does not appear to be a string"); + //UNEXPECTED; } } #endif @@ -1410,7 +1411,8 @@ void Checker::check_struct(const ToCheck & item) } else { - UNEXPECTED; + FAIL("unknown allocation size; possibly bad"); + //UNEXPECTED; } } From e3569257959389c3910a547a8ecfde32d5b7afbd Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 2 Mar 2020 23:12:03 -0600 Subject: [PATCH 09/15] update structures --- library/Types.cpp | 2 +- library/modules/Items.cpp | 2 +- library/modules/Job.cpp | 4 ++-- library/xml | 2 +- plugins/stocks.cpp | 10 +++++----- plugins/workflow.cpp | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/Types.cpp b/library/Types.cpp index 5067c32ae..420f3b866 100644 --- a/library/Types.cpp +++ b/library/Types.cpp @@ -127,7 +127,7 @@ bool DFHack::removeRef(std::vector &vec, df::specific_ref_typ for (int i = vec.size()-1; i >= 0; i--) { df::specific_ref *ref = vec[i]; - if (ref->type != type || ref->object != ptr) + if (ref->type != type || ref->data.object != ptr) continue; vector_erase_at(vec, i); diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index a1b4ace4d..4939aa9dd 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -658,7 +658,7 @@ df::coord Items::getPosition(df::item *item) switch (ref->type) { case specific_ref_type::VERMIN_ESCAPED_PET: - return ref->vermin->pos; + return ref->data.VERMIN_ESCAPED_PET->pos; default: break; diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp index 7673737b2..d0487941f 100644 --- a/library/modules/Job.cpp +++ b/library/modules/Job.cpp @@ -311,7 +311,7 @@ void DFHack::Job::disconnectJobItem(df::job *job, df::job_item_ref *ref) { auto ref = item->specific_refs[refIndex]; if (ref->type == df::specific_ref_type::JOB) { - if (ref->job == job) { + if (ref->data.JOB == job) { vector_erase_at(item->specific_refs, refIndex); delete ref; } else { @@ -579,7 +579,7 @@ bool DFHack::Job::attachJobItem(df::job *job, df::item *item, auto item_link = new df::specific_ref(); item_link->type = specific_ref_type::JOB; - item_link->job = job; + item_link->data.JOB = job; item->specific_refs.push_back(item_link); auto job_link = new df::job_item_ref(); diff --git a/library/xml b/library/xml index 5653a57e0..61eed9280 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 5653a57e0978a78c1f1ef125b63359fefa7660f2 +Subproject commit 61eed9280adfb51dde777c9e8f8549a4d72e868b diff --git a/plugins/stocks.cpp b/plugins/stocks.cpp index b5831d159..d9ec97c0d 100644 --- a/plugins/stocks.cpp +++ b/plugins/stocks.cpp @@ -179,8 +179,8 @@ static map items_in_cages; static df::job *get_item_job(df::item *item) { auto ref = Items::getSpecificRef(item, specific_ref_type::JOB); - if (ref && ref->job) - return ref->job; + if (ref && ref->data.JOB) + return ref->data.JOB; return nullptr; } @@ -1008,12 +1008,12 @@ private: if (item->flags.bits.in_job) { auto ref = Items::getSpecificRef(item, specific_ref_type::JOB); - if (ref && ref->job) + if (ref && ref->data.JOB) { - if (ref->job->job_type == job_type::Eat || ref->job->job_type == job_type::Drink) + if (ref->data.JOB->job_type == job_type::Eat || ref->data.JOB->job_type == job_type::Drink) return pos; - auto unit = Job::getWorker(ref->job); + auto unit = Job::getWorker(ref->data.JOB); if (unit) return unit->pos; } diff --git a/plugins/workflow.cpp b/plugins/workflow.cpp index 18490039e..3e31d14ab 100644 --- a/plugins/workflow.cpp +++ b/plugins/workflow.cpp @@ -1151,10 +1151,10 @@ static bool itemInRealJob(df::item *item) return false; auto ref = Items::getSpecificRef(item, specific_ref_type::JOB); - if (!ref || !ref->job) + if (!ref || !ref->data.JOB) return true; - return ENUM_ATTR(job_type, type, ref->job->job_type) + return ENUM_ATTR(job_type, type, ref->data.JOB->job_type) != job_type_class::Hauling; } From 676e73d4770c129b4a78569f56fcf1b58f7e7389 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 2 Mar 2020 23:59:55 -0600 Subject: [PATCH 10/15] update structures --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 61eed9280..a51aa1e71 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 61eed9280adfb51dde777c9e8f8549a4d72e868b +Subproject commit a51aa1e71450abf01b760d7708469c4c12173a59 From 6d15d349bc8435baffdc846691f393102e04fe09 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Tue, 3 Mar 2020 21:45:13 -0600 Subject: [PATCH 11/15] update structures --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index a51aa1e71..13449a3c7 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit a51aa1e71450abf01b760d7708469c4c12173a59 +Subproject commit 13449a3c70b08d182d14900133b21db795dd6cca From 08e1fe1f02694fc63677610b472c17f92537ec15 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Tue, 3 Mar 2020 22:42:40 -0600 Subject: [PATCH 12/15] update structures --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 13449a3c7..f54a38004 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 13449a3c70b08d182d14900133b21db795dd6cca +Subproject commit f54a380047ab774987b89a1b5021231e44cbe49e From 864264aec049bbe588f68e9d7ca042b6fb1de5ca Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Wed, 4 Mar 2020 13:17:29 -0600 Subject: [PATCH 13/15] update scripts --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 76d84e1ae..7bab11642 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 76d84e1aed23e3ec1690037ea3454f920b60d86a +Subproject commit 7bab11642bee7a3aa05d69332466f2ea5eaa1a2d From 84cae060b1cd86b0cef5d8c5d2da44f70ecb3a02 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Wed, 4 Mar 2020 18:23:49 -0600 Subject: [PATCH 14/15] move find_union_tag from check-structures-sanity to DataDefs.h --- library/DataDefs.cpp | 87 ++++++++++++++++ library/include/DataDefs.h | 10 ++ plugins/devel/check-structures-sanity.cpp | 118 ++-------------------- 3 files changed, 106 insertions(+), 109 deletions(-) diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index 92bd19fd4..cd3474619 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -454,3 +454,90 @@ void DFHack::flagarrayToString(std::vector *pvec, const void *p, } } } + +static const struct_field_info *find_union_tag_candidate(const struct_field_info *fields, const struct_field_info *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"; + + for (auto field = fields; field->mode != struct_field_info::END; field++) + { + if (field->name == name) + { + return field; + } + } + } + + 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; +} + +const struct_field_info *DFHack::find_union_tag(const struct_field_info *fields, const struct_field_info *union_field) +{ + CHECK_NULL_POINTER(fields); + CHECK_NULL_POINTER(union_field); + + auto tag_candidate = find_union_tag_candidate(fields, union_field); + + if (union_field->mode == struct_field_info::SUBSTRUCT && + union_field->type && + union_field->type->type() == IDTYPE_UNION) + { + // union field + + if (tag_candidate->mode == struct_field_info::PRIMITIVE && + tag_candidate->type && + tag_candidate->type->type() == IDTYPE_ENUM) + { + return tag_candidate; + } + + return nullptr; + } + + if (union_field->mode != struct_field_info::CONTAINER || + !union_field->type || + union_field->type->type() != IDTYPE_CONTAINER) + { + // not a union field or a vector; bail + return nullptr; + } + + auto container_type = static_cast(union_field->type); + if (container_type->getFullName(nullptr) != "vector" || + !container_type->getItemType() || + container_type->getItemType()->type() != IDTYPE_UNION) + { + // not a vector of unions + return nullptr; + } + + if (tag_candidate->mode != struct_field_info::CONTAINER || + !tag_candidate->type || + tag_candidate->type->type() != IDTYPE_CONTAINER) + { + // candidate is not a vector + return nullptr; + } + + auto tag_container_type = static_cast(tag_candidate->type); + if (tag_container_type->getFullName(nullptr) == "vector" && + tag_container_type->getItemType() && + tag_container_type->getItemType()->type() == IDTYPE_ENUM) + { + return tag_candidate; + } + + return nullptr; +} diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index f772629cf..704b1abf7 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -796,6 +796,16 @@ namespace DFHack { flagarray_to_string(&tmp, val); return join_strings(sep, tmp); } + + /** + * Finds the tag field for a given union field. + * + * The returned tag field is a primitive enum field or nullptr. + * + * If the union field is a container type, the returned tag field is + * a container of primitive enum types. + */ + DFHACK_EXPORT const struct_field_info *find_union_tag(const struct_field_info *fields, const struct_field_info *union_field); } #define ENUM_ATTR(enum,attr,val) (df::enum_traits::attrs(val).attr) diff --git a/plugins/devel/check-structures-sanity.cpp b/plugins/devel/check-structures-sanity.cpp index 1d832aaac..b5cd1aa5f 100644 --- a/plugins/devel/check-structures-sanity.cpp +++ b/plugins/devel/check-structures-sanity.cpp @@ -97,97 +97,6 @@ static const char *const *get_enum_item_key(enum_identity *identity, int64_t val return &identity->getKeys()[index]; } -static const struct_field_info *find_union_tag_field(const struct_field_info *fields, const struct_field_info *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"; - - for (auto field = fields; field->mode != struct_field_info::END; field++) - { - if (field->name == name) - { - return field; - } - } - } - - 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) - { - // 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 || - !tag_field->type || - tag_field->type->type() != IDTYPE_ENUM) - { - // no tag - return nullptr; - } - - return tag_field; -} - -static const struct_field_info *find_union_vector_tag_vector(const struct_field_info *fields, const struct_field_info *union_field) -{ - if (union_field->mode != struct_field_info::CONTAINER || - !union_field->type || - union_field->type->type() != IDTYPE_CONTAINER) - { - // not a vector - return nullptr; - } - - auto container_type = static_cast(union_field->type); - if (container_type->getFullName(nullptr) != "vector" || - !container_type->getItemType() || - container_type->getItemType()->type() != IDTYPE_UNION) - { - // 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::CONTAINER || - !tag_field->type || - tag_field->type->type() != IDTYPE_CONTAINER) - { - // no tag vector - return nullptr; - } - - auto tag_container_type = static_cast(tag_field->type); - if (tag_container_type->getFullName(nullptr) != "vector" || - !tag_container_type->getItemType() || - tag_container_type->getItemType()->type() != IDTYPE_ENUM) - { - // not an enum - return nullptr; - } - - return tag_field; -} - struct ToCheck { std::vector path; @@ -693,27 +602,18 @@ void Checker::queue_static_array(const ToCheck & array, void *base, type_identit bool Checker::maybe_queue_union(const ToCheck & item, const struct_field_info *fields, const struct_field_info *union_field) { auto tag_field = find_union_tag(fields, union_field); - if (tag_field) - { - ToCheck union_item(item, "." + std::string(union_field->name), PTR_ADD(item.ptr, union_field->offset), union_field->type); - ToCheck tag_item(item, "." + std::string(tag_field->name), PTR_ADD(item.ptr, tag_field->offset), tag_field->type); - queue_union(union_item, tag_item); - - return true; - } - - tag_field = find_union_vector_tag_vector(fields, union_field); - if (tag_field) - { - ToCheck union_vector_item(item, "." + std::string(union_field->name), PTR_ADD(item.ptr, union_field->offset), union_field->type); - ToCheck tag_vector_item(item, "." + std::string(tag_field->name), PTR_ADD(item.ptr, tag_field->offset), tag_field->type); + if (!tag_field) + return false; - queue_union_vector(union_vector_item, tag_vector_item); + ToCheck union_item(item, "." + std::string(union_field->name), PTR_ADD(item.ptr, union_field->offset), union_field->type); + ToCheck tag_item(item, "." + std::string(tag_field->name), PTR_ADD(item.ptr, tag_field->offset), tag_field->type); - return true; - } + if (union_field->mode == struct_field_info::SUBSTRUCT) + queue_union(union_item, tag_item); + else + queue_union_vector(union_item, tag_item); - return false; + return true; } void Checker::queue_union(const ToCheck & item, const ToCheck & tag_item) From 885fa541fd432ef29f97807ec15429a3b6d31762 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Thu, 5 Mar 2020 00:06:32 -0600 Subject: [PATCH 15/15] update structures --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index f54a38004..167d54bf7 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f54a380047ab774987b89a1b5021231e44cbe49e +Subproject commit 167d54bf7c0e01a71ffb2de548701adc93da9dad