Schema: Some infinite loop avoidance

- Detect obvious cases of inheritance loops
- Don't try to keep track of tags with a super tag that exist within a conditional tag
- When searching for a tag path, don't append the leaf to the full path
This commit is contained in:
Celtic Minstrel 2022-07-22 22:27:03 -04:00
parent 6c30ef4b20
commit b57b1188c0
2 changed files with 30 additions and 4 deletions

View file

@ -158,6 +158,19 @@ static void duplicate_key_error(const std::string& file,
print_output(ss.str(), flag_exception);
}
static void inheritance_loop_error(const std::string& file,
int line,
const std::string& tag,
const std::string& key,
const std::string& value,
int index,
bool flag_exception)
{
std::ostringstream ss;
ss << "Inheritance loop " << key << "=" << value << " found (at offset " << index << ") in tag [" << tag << "]\n" << at(file, line) << "\n";
print_output(ss.str(), flag_exception);
}
static void wrong_type_error(const std::string & file, int line,
const std::string & tag,
const std::string & key,
@ -464,11 +477,14 @@ bool schema_self_validator::tag_path_exists(const config& cfg, const reference&
suffix = path.back();
//suffix = link->second + "/" + suffix;
} else {
auto supers = derivations_.equal_range(prefix);
const auto supers = derivations_.equal_range(prefix);
if(supers.first != supers.second) {
reference super_ref = ref;
for( ; supers.first != supers.second; ++supers.first) {
super_ref.value_ = supers.first->second + "/" + suffix;
for(auto cur = supers.first ; cur != supers.second; ++cur) {
super_ref.value_ = cur->second + "/" + suffix;
if(super_ref.value_.find(ref.value_) == 0) {
continue;
}
if(tag_path_exists(cfg, super_ref)) {
return true;
}
@ -588,6 +604,13 @@ void schema_self_validator::validate_key(const config& cfg, const std::string& n
} else if(tag_name == "tag" && name == "super") {
for(auto super : utils::split(cfg["super"])) {
referenced_tag_paths_.emplace_back(super, file, start_line, tag_name);
if(condition_nesting_ > 0) {
continue;
}
if(current_path() == super) {
queue_message(cfg, SUPER_LOOP, file, start_line, cfg["super"].str().find(super), tag_name, "super", super);
continue;
}
derivations_.emplace(current_path(), super);
}
} else if(condition_nesting_ == 0 && tag_name == "tag" && name == "name") {
@ -643,6 +666,9 @@ void schema_self_validator::print(message_info& el)
case DUPLICATE_KEY:
duplicate_key_error(el.file, el.line, el.tag, el.key, el.value, create_exceptions_);
break;
case SUPER_LOOP:
inheritance_loop_error(el.file, el.line, el.tag, el.key, el.value, el.n, create_exceptions_);
break;
}
}

View file

@ -194,7 +194,7 @@ private:
static bool name_matches(const std::string& pattern, const std::string& name);
void print(message_info& message) override;
enum { WRONG_TYPE = NEXT_ERROR, WRONG_PATH, DUPLICATE_TAG, DUPLICATE_KEY, NEXT_ERROR };
enum { WRONG_TYPE = NEXT_ERROR, WRONG_PATH, DUPLICATE_TAG, DUPLICATE_KEY, SUPER_LOOP, NEXT_ERROR };
};
} // namespace schema_validation{