in source/Rules.cpp [47:117]
void Rules::add(Context& context, std::unique_ptr<Rule> rule) {
auto existing = rules_.find(rule->code());
if (existing != rules_.end()) {
ERROR(
1,
"A rule for code {} already exists! Duplicate rules are:\n{}\n{}",
rule->code(),
JsonValidation::to_styled_string(rule->to_json()),
JsonValidation::to_styled_string(existing->second->to_json()));
return;
}
auto code = rule->code();
auto result = rules_.emplace(code, std::move(rule));
const Rule* rule_pointer = result.first->second.get();
if (auto* source_sink_rule = rule_pointer->as<SourceSinkRule>()) {
for (const auto* source_kind : source_sink_rule->source_kinds()) {
for (const auto* sink_kind : source_sink_rule->sink_kinds()) {
source_to_sink_to_rules_[source_kind][sink_kind].push_back(
rule_pointer);
}
}
} else if (
const auto* multi_source_rule =
rule_pointer->as<MultiSourceMultiSinkRule>()) {
// Consider the rule:
// Code: 1000
// Sources: { lblA: [SourceA], lblB: [SourceB] }
// Sinks: [ Partial(SinkX, lblA), Partial(SinkX, lblB) ]
//
// A flow like SourceA -> Partial(SinkX, lblA) fulfills half the rule
// (tracked in `source_to_partial_sink_to_rules_`).
//
// When a half-fulfilled rule is seen, the analysis creates a triggered
// partial sink:
// B = Triggered(SinkX, lblB, rule: 1000)
//
// The rule is completely fulfilled when "SourceB -> B" is detected,
// which is what `source_to_sink_to_rules_` tracks.
//
// Tracking the rule in the triggered sink is necessary because there can
// be another rule with the same sinks but different sources:
// Code: 2000
// Sources: { lblA: [SourceC], lblB: [SourceB] }
// Sinks: [ Partial(SinkX, lblA), Partial(SinkX, lblB) ]
//
// Without the rule, we cannot tell which rule is satisfied:
// SourceB -> Triggered(SinkX, lblB) can match either rule.
// With the rule, it is clear that only the first rule applies:
// SourceB -> Triggered(SinkX, lblB, rule: 1000)
for (const auto& [source_label, source_kinds] :
multi_source_rule->multi_source_kinds()) {
for (const auto* source_kind : source_kinds) {
for (const auto* sink_kind :
multi_source_rule->partial_sink_kinds(source_label)) {
const auto* triggered =
context.kinds->get_triggered(sink_kind, multi_source_rule);
source_to_partial_sink_to_rules_[source_kind][sink_kind].push_back(
multi_source_rule);
source_to_sink_to_rules_[source_kind][triggered].push_back(
multi_source_rule);
}
}
}
} else {
// Unreachable code. Did we add a new type of rule?
mt_unreachable();
}
}