mirror of
https://github.com/zeek/zeek.git
synced 2025-10-12 03:28:19 +00:00
working through complex testing scenarios
This commit is contained in:
parent
a4e5617105
commit
5bd4da72f9
4 changed files with 135 additions and 80 deletions
|
@ -1003,10 +1003,6 @@ void ProfileFuncs::ComputeSideEffects() {
|
||||||
// Weed out very-common-and-completely-safe expressions.
|
// Weed out very-common-and-completely-safe expressions.
|
||||||
if ( ! DefinitelyHasNoSideEffects(a->GetExpr()) )
|
if ( ! DefinitelyHasNoSideEffects(a->GetExpr()) )
|
||||||
candidates.insert(a);
|
candidates.insert(a);
|
||||||
#if 0
|
|
||||||
else
|
|
||||||
printf("attribute %s definitely has no side effects\n", obj_desc(a).c_str());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1015,7 +1011,7 @@ void ProfileFuncs::ComputeSideEffects() {
|
||||||
std::vector<std::shared_ptr<SideEffectsOp>> side_effects;
|
std::vector<std::shared_ptr<SideEffectsOp>> side_effects;
|
||||||
|
|
||||||
while ( ! candidates.empty() ) {
|
while ( ! candidates.empty() ) {
|
||||||
std::unordered_set<const Attr*> made_decision;
|
AttrSet made_decision;
|
||||||
|
|
||||||
for ( auto c : candidates ) {
|
for ( auto c : candidates ) {
|
||||||
IDSet non_local_ids;
|
IDSet non_local_ids;
|
||||||
|
@ -1055,8 +1051,9 @@ void ProfileFuncs::SetSideEffects(const Attr* a, IDSet& non_local_ids, TypeSet&
|
||||||
bool is_rec = expr_attrs[a][0]->Tag() == TYPE_RECORD;
|
bool is_rec = expr_attrs[a][0]->Tag() == TYPE_RECORD;
|
||||||
|
|
||||||
SideEffectsOp::AccessType at;
|
SideEffectsOp::AccessType at;
|
||||||
if ( is_rec )
|
if ( is_rec ) {
|
||||||
at = SideEffectsOp::CONSTRUCTION;
|
at = SideEffectsOp::CONSTRUCTION;
|
||||||
|
}
|
||||||
else if ( a->Tag() == ATTR_ON_CHANGE )
|
else if ( a->Tag() == ATTR_ON_CHANGE )
|
||||||
at = SideEffectsOp::WRITE;
|
at = SideEffectsOp::WRITE;
|
||||||
else
|
else
|
||||||
|
@ -1069,6 +1066,7 @@ void ProfileFuncs::SetSideEffects(const Attr* a, IDSet& non_local_ids, TypeSet&
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// printf("%s has side effects\n", obj_desc(a).c_str());
|
// printf("%s has side effects\n", obj_desc(a).c_str());
|
||||||
|
attrs_with_side_effects.insert(a);
|
||||||
|
|
||||||
for ( auto ea_t : expr_attrs[a] ) {
|
for ( auto ea_t : expr_attrs[a] ) {
|
||||||
auto seo = std::make_shared<SideEffectsOp>(at, ea_t);
|
auto seo = std::make_shared<SideEffectsOp>(at, ea_t);
|
||||||
|
@ -1078,6 +1076,8 @@ void ProfileFuncs::SetSideEffects(const Attr* a, IDSet& non_local_ids, TypeSet&
|
||||||
if ( is_unknown )
|
if ( is_unknown )
|
||||||
seo->SetUnknownChanges();
|
seo->SetUnknownChanges();
|
||||||
|
|
||||||
|
// printf("adding to side effects ops (%lu) for type: %s\n", aggrs.size(), obj_desc(ea_t).c_str());
|
||||||
|
// for ( auto a : aggrs ) printf(" aggr type %s\n", obj_desc(a).c_str());
|
||||||
side_effects_ops.push_back(seo);
|
side_effects_ops.push_back(seo);
|
||||||
seo_vec.push_back(std::move(seo));
|
seo_vec.push_back(std::move(seo));
|
||||||
}
|
}
|
||||||
|
@ -1115,21 +1115,29 @@ bool ProfileFuncs::DefinitelyHasNoSideEffects(const ExprPtr& e) const {
|
||||||
std::vector<const Attr*> ProfileFuncs::AssociatedAttrs(const Type* t) {
|
std::vector<const Attr*> ProfileFuncs::AssociatedAttrs(const Type* t) {
|
||||||
std::vector<const Attr*> assoc_attrs;
|
std::vector<const Attr*> assoc_attrs;
|
||||||
|
|
||||||
for ( auto c : candidates )
|
FindAssociatedAttrs(candidates, t, assoc_attrs);
|
||||||
for ( auto ea_t : expr_attrs[c] ) {
|
FindAssociatedAttrs(attrs_with_side_effects, t, assoc_attrs);
|
||||||
|
|
||||||
|
return assoc_attrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileFuncs::FindAssociatedAttrs(const AttrSet& candidate_attrs, const Type* t,
|
||||||
|
std::vector<const Attr*>& assoc_attrs) {
|
||||||
|
for ( auto a : candidate_attrs ) {
|
||||||
|
// printf("... candidate has %lu exprs\n", expr_attrs[a].size());
|
||||||
|
for ( auto ea_t : expr_attrs[a] ) {
|
||||||
if ( same_type(t, ea_t) ) {
|
if ( same_type(t, ea_t) ) {
|
||||||
assoc_attrs.push_back(c);
|
assoc_attrs.push_back(a);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( auto ta : type_aliases[ea_t] )
|
for ( auto ta : type_aliases[ea_t] )
|
||||||
if ( same_type(t, ta) ) {
|
if ( same_type(t, ta) ) {
|
||||||
assoc_attrs.push_back(c);
|
assoc_attrs.push_back(a);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return assoc_attrs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProfileFuncs::AssessSideEffects(const ExprPtr& e, IDSet& non_local_ids, TypeSet& aggrs, bool& is_unknown) {
|
bool ProfileFuncs::AssessSideEffects(const ExprPtr& e, IDSet& non_local_ids, TypeSet& aggrs, bool& is_unknown) {
|
||||||
|
@ -1141,6 +1149,7 @@ bool ProfileFuncs::AssessSideEffects(const ExprPtr& e, IDSet& non_local_ids, Typ
|
||||||
ASSERT(expr_profs.count(e.get()) != 0);
|
ASSERT(expr_profs.count(e.get()) != 0);
|
||||||
pf = expr_profs[e.get()];
|
pf = expr_profs[e.get()];
|
||||||
|
|
||||||
|
// printf("doing attr expr %s\n", obj_desc(e.get()).c_str());
|
||||||
return AssessSideEffects(pf.get(), non_local_ids, aggrs, is_unknown);
|
return AssessSideEffects(pf.get(), non_local_ids, aggrs, is_unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1157,49 +1166,73 @@ bool ProfileFuncs::AssessSideEffects(const ProfileFunc* pf, IDSet& non_local_ids
|
||||||
IDSet nla;
|
IDSet nla;
|
||||||
TypeSet mod_aggrs;
|
TypeSet mod_aggrs;
|
||||||
|
|
||||||
for ( auto& a : pf->NonLocalAssignees() )
|
for ( auto& a : pf->NonLocalAssignees() ) {
|
||||||
|
// printf("adding assignee %s\n", a->Name());
|
||||||
nla.insert(a);
|
nla.insert(a);
|
||||||
|
}
|
||||||
|
|
||||||
for ( auto& r : pf->RecordConstructorAttrs() )
|
for ( auto& r : pf->RecordConstructorAttrs() ) {
|
||||||
if ( ! AssessAggrEffects(SideEffectsOp::CONSTRUCTION, r.first, nla, mod_aggrs, is_unknown) )
|
// printf("doing record constructor attr (%d): %s\n", is_unknown, obj_desc(r.first).c_str());
|
||||||
|
if ( ! AssessAggrEffects(SideEffectsOp::CONSTRUCTION, r.first, nla, mod_aggrs, is_unknown) ) {
|
||||||
// You'd think we would return "false" here, because we don't have
|
// You'd think we would return "false" here, because we don't have
|
||||||
// enough information yet to know all of the side effects. However,
|
// enough information yet to know all of the side effects. However,
|
||||||
// if "is_unknown" is true then that means there are already
|
// if "is_unknown" is true then that means there are already
|
||||||
// wildcard side effects, so there's no need to analyze further
|
// wildcard side effects, so there's no need to analyze further
|
||||||
// since it won't change that situation.
|
// since it won't change that situation.
|
||||||
|
// printf("record construction assess failed, returning %d\n", is_unknown);
|
||||||
return is_unknown;
|
return is_unknown;
|
||||||
|
}
|
||||||
|
// printf("done: %lu/%lu\n", nla.size(), mod_aggrs.size());
|
||||||
|
}
|
||||||
|
|
||||||
for ( auto& tr : pf->TableRefs() )
|
for ( auto& tr : pf->TableRefs() ) {
|
||||||
if ( ! AssessAggrEffects(SideEffectsOp::READ, tr, nla, mod_aggrs, is_unknown) )
|
// printf("doing table ref %s\n", obj_desc(tr).c_str());
|
||||||
|
if ( ! AssessAggrEffects(SideEffectsOp::READ, tr, nla, mod_aggrs, is_unknown) ) {
|
||||||
|
// printf("table read assess failed, returning %d\n", is_unknown);
|
||||||
return is_unknown;
|
return is_unknown;
|
||||||
|
}
|
||||||
|
// printf("done: %lu/%lu\n", nla.size(), mod_aggrs.size());
|
||||||
|
}
|
||||||
|
|
||||||
for ( auto& tm : pf->AggrMods() ) {
|
for ( auto& tm : pf->AggrMods() ) {
|
||||||
if ( tm->Tag() == TYPE_TABLE && ! AssessAggrEffects(SideEffectsOp::WRITE, tm, nla, mod_aggrs, is_unknown) )
|
// printf("doing table mod %s\n", obj_desc(tm).c_str());
|
||||||
|
if ( tm->Tag() == TYPE_TABLE && ! AssessAggrEffects(SideEffectsOp::WRITE, tm, nla, mod_aggrs, is_unknown) ) {
|
||||||
|
// printf("table mod assess failed, returning %d\n", is_unknown);
|
||||||
return is_unknown;
|
return is_unknown;
|
||||||
|
}
|
||||||
|
|
||||||
mod_aggrs.insert(tm);
|
mod_aggrs.insert(tm);
|
||||||
|
// printf("done: %lu/%lu\n", nla.size(), mod_aggrs.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( auto& f : pf->ScriptCalls() ) {
|
for ( auto& f : pf->ScriptCalls() ) {
|
||||||
|
// printf("doing script call %s\n", f->Name());
|
||||||
if ( f->Flavor() != FUNC_FLAVOR_FUNCTION ) {
|
if ( f->Flavor() != FUNC_FLAVOR_FUNCTION ) {
|
||||||
// A hook (since events can't be called) - not something
|
// A hook (since events can't be called) - not something
|
||||||
// to analyze further.
|
// to analyze further.
|
||||||
|
// printf("flavor failed, returning %d\n", is_unknown);
|
||||||
is_unknown = true;
|
is_unknown = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pff = func_profs[f];
|
auto pff = func_profs[f];
|
||||||
if ( active_func_profiles.count(pff) > 0 )
|
if ( active_func_profiles.count(pff) > 0 ) {
|
||||||
|
// printf("pruned by recursion\n");
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
active_func_profiles.insert(pff);
|
active_func_profiles.insert(pff);
|
||||||
auto a = AssessSideEffects(pff.get(), nla, mod_aggrs, is_unknown);
|
auto a = AssessSideEffects(pff.get(), nla, mod_aggrs, is_unknown);
|
||||||
|
// printf("done: %lu/%lu\n", nla.size(), mod_aggrs.size());
|
||||||
active_func_profiles.erase(pff);
|
active_func_profiles.erase(pff);
|
||||||
|
|
||||||
if ( ! a )
|
if ( ! a ) {
|
||||||
|
// printf("assess failed, returning %d\n", is_unknown);
|
||||||
return is_unknown;
|
return is_unknown;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// printf("FINAL: %lu/%lu\n", nla.size(), mod_aggrs.size());
|
||||||
non_local_ids.insert(nla.begin(), nla.end());
|
non_local_ids.insert(nla.begin(), nla.end());
|
||||||
aggrs.insert(mod_aggrs.begin(), mod_aggrs.end());
|
aggrs.insert(mod_aggrs.begin(), mod_aggrs.end());
|
||||||
|
|
||||||
|
@ -1210,7 +1243,11 @@ bool ProfileFuncs::AssessAggrEffects(SideEffectsOp::AccessType access, const Typ
|
||||||
TypeSet& aggrs, bool& is_unknown) {
|
TypeSet& aggrs, bool& is_unknown) {
|
||||||
auto assoc_attrs = AssociatedAttrs(t);
|
auto assoc_attrs = AssociatedAttrs(t);
|
||||||
|
|
||||||
|
// if ( access == SideEffectsOp::READ ) printf("assessing %lu attrs for type %s (%lu, %lu, %d)\n",
|
||||||
|
// assoc_attrs.size(), obj_desc(t).c_str(), non_local_ids.size(), aggrs.size(), is_unknown);
|
||||||
|
|
||||||
for ( auto a : assoc_attrs ) {
|
for ( auto a : assoc_attrs ) {
|
||||||
|
// printf("... assessing (%d) attr: %s\n", a == curr_candidate, obj_desc(a).c_str());
|
||||||
if ( a == curr_candidate )
|
if ( a == curr_candidate )
|
||||||
// ###
|
// ###
|
||||||
continue;
|
continue;
|
||||||
|
@ -1218,15 +1255,20 @@ bool ProfileFuncs::AssessAggrEffects(SideEffectsOp::AccessType access, const Typ
|
||||||
auto ase = attr_side_effects.find(a);
|
auto ase = attr_side_effects.find(a);
|
||||||
if ( ase == attr_side_effects.end() ) {
|
if ( ase == attr_side_effects.end() ) {
|
||||||
ase = record_constr_with_side_effects.find(a);
|
ase = record_constr_with_side_effects.find(a);
|
||||||
if ( ase == record_constr_with_side_effects.end() )
|
if ( ase == record_constr_with_side_effects.end() ) {
|
||||||
|
// printf("... ... didn't find it\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
for ( auto& se : ase->second )
|
|
||||||
if ( AssessSideEffects(se.get(), access, t, non_local_ids, aggrs) ) {
|
|
||||||
is_unknown = true;
|
|
||||||
return true; // no point doing any more work
|
|
||||||
}
|
}
|
||||||
|
// printf("... ... found it for record construction (%lu)\n", ase->second.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// printf("... ... found it for side effects (%lu)\n", ase->second.size());
|
||||||
|
|
||||||
|
for ( auto& se : ase->second )
|
||||||
|
if ( AssessSideEffects(se.get(), access, t, non_local_ids, aggrs) ) {
|
||||||
|
is_unknown = true;
|
||||||
|
return true; // no point doing any more work
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1280,9 +1322,15 @@ bool ProfileFuncs::HasSideEffects(SideEffectsOp::AccessType access, const TypePt
|
||||||
|
|
||||||
bool ProfileFuncs::GetSideEffects(SideEffectsOp::AccessType access, const Type* t, IDSet& non_local_ids,
|
bool ProfileFuncs::GetSideEffects(SideEffectsOp::AccessType access, const Type* t, IDSet& non_local_ids,
|
||||||
TypeSet& aggrs) const {
|
TypeSet& aggrs) const {
|
||||||
for ( auto se : side_effects_ops )
|
for ( auto se : side_effects_ops ) {
|
||||||
if ( AssessSideEffects(se.get(), access, t, non_local_ids, aggrs) )
|
if ( access == SideEffectsOp::CONSTRUCTION )
|
||||||
|
printf("doing a construction side effects check: %lu\n", side_effects_ops.size());
|
||||||
|
if ( AssessSideEffects(se.get(), access, t, non_local_ids, aggrs) ) {
|
||||||
|
// if ( access == SideEffectsOp::CONSTRUCTION ) printf("construction side effects true\n");
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if ( access == SideEffectsOp::CONSTRUCTION ) printf("construction answer is false\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -386,7 +386,11 @@ protected:
|
||||||
|
|
||||||
bool DefinitelyHasNoSideEffects(const ExprPtr& e) const;
|
bool DefinitelyHasNoSideEffects(const ExprPtr& e) const;
|
||||||
|
|
||||||
|
// ### more using
|
||||||
|
using AttrSet = std::unordered_set<const Attr*>;
|
||||||
|
|
||||||
std::vector<const Attr*> AssociatedAttrs(const Type* t);
|
std::vector<const Attr*> AssociatedAttrs(const Type* t);
|
||||||
|
void FindAssociatedAttrs(const AttrSet& candidate_attrs, const Type* t, std::vector<const Attr*>& assoc_attrs);
|
||||||
|
|
||||||
// ### False on can't-make-decision-yet
|
// ### False on can't-make-decision-yet
|
||||||
bool AssessSideEffects(const ExprPtr& e, IDSet& non_local_ids, TypeSet& types, bool& is_unknown);
|
bool AssessSideEffects(const ExprPtr& e, IDSet& non_local_ids, TypeSet& types, bool& is_unknown);
|
||||||
|
@ -465,7 +469,8 @@ protected:
|
||||||
// not provided via accessors:
|
// not provided via accessors:
|
||||||
|
|
||||||
// ###
|
// ###
|
||||||
std::unordered_set<const Attr*> candidates;
|
AttrSet candidates;
|
||||||
|
AttrSet attrs_with_side_effects;
|
||||||
|
|
||||||
// ###
|
// ###
|
||||||
const Attr* curr_candidate;
|
const Attr* curr_candidate;
|
||||||
|
|
|
@ -901,10 +901,8 @@ TraversalCode CSE_ValidityChecker::PreExpr(const Expr* e) {
|
||||||
auto lhs_ref = e->GetOp1()->AsRefExprPtr();
|
auto lhs_ref = e->GetOp1()->AsRefExprPtr();
|
||||||
auto lhs = lhs_ref->GetOp1()->AsNameExpr();
|
auto lhs = lhs_ref->GetOp1()->AsNameExpr();
|
||||||
|
|
||||||
if ( CheckID(lhs->Id(), false) ) {
|
if ( CheckID(lhs->Id(), false) )
|
||||||
is_valid = false;
|
|
||||||
return TC_ABORTALL;
|
return TC_ABORTALL;
|
||||||
}
|
|
||||||
|
|
||||||
// Note, we don't use CheckAggrMod() because this is a plain
|
// Note, we don't use CheckAggrMod() because this is a plain
|
||||||
// assignment. It might be changing a variable's binding to
|
// assignment. It might be changing a variable's binding to
|
||||||
|
@ -921,10 +919,8 @@ TraversalCode CSE_ValidityChecker::PreExpr(const Expr* e) {
|
||||||
auto lhs_aggr = e->GetOp1();
|
auto lhs_aggr = e->GetOp1();
|
||||||
auto lhs_aggr_id = lhs_aggr->AsNameExpr()->Id();
|
auto lhs_aggr_id = lhs_aggr->AsNameExpr()->Id();
|
||||||
|
|
||||||
if ( CheckID(lhs_aggr_id, true) || CheckTableMod(lhs_aggr->GetType()) ) {
|
if ( CheckID(lhs_aggr_id, true) || CheckTableMod(lhs_aggr->GetType()) )
|
||||||
is_valid = false;
|
|
||||||
return TC_ABORTALL;
|
return TC_ABORTALL;
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case EXPR_FIELD_LHS_ASSIGN: {
|
case EXPR_FIELD_LHS_ASSIGN: {
|
||||||
|
@ -932,26 +928,20 @@ TraversalCode CSE_ValidityChecker::PreExpr(const Expr* e) {
|
||||||
auto lhs_aggr_id = lhs->AsNameExpr()->Id();
|
auto lhs_aggr_id = lhs->AsNameExpr()->Id();
|
||||||
auto lhs_field = e->AsFieldLHSAssignExpr()->Field();
|
auto lhs_field = e->AsFieldLHSAssignExpr()->Field();
|
||||||
|
|
||||||
if ( CheckID(lhs_aggr_id, true) || (lhs_field == field && same_type(lhs_aggr_id->GetType(), field_type)) ) {
|
if ( CheckID(lhs_aggr_id, true) || (lhs_field == field && same_type(lhs_aggr_id->GetType(), field_type)) )
|
||||||
is_valid = false;
|
|
||||||
return TC_ABORTALL;
|
return TC_ABORTALL;
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case EXPR_APPEND_TO:
|
case EXPR_APPEND_TO:
|
||||||
// This doesn't directly change any identifiers, but does
|
// This doesn't directly change any identifiers, but does
|
||||||
// alter an aggregate.
|
// alter an aggregate.
|
||||||
if ( CheckAggrMod(e->GetType()) ) {
|
if ( CheckAggrMod(e->GetType()) )
|
||||||
is_valid = false;
|
|
||||||
return TC_ABORTALL;
|
return TC_ABORTALL;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXPR_CALL:
|
case EXPR_CALL:
|
||||||
if ( CheckCall(e->AsCallExpr()) ) {
|
if ( CheckCall(e->AsCallExpr()) )
|
||||||
is_valid = false;
|
|
||||||
return TC_ABORTALL;
|
return TC_ABORTALL;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXPR_TABLE_CONSTRUCTOR:
|
case EXPR_TABLE_CONSTRUCTOR:
|
||||||
|
@ -966,10 +956,8 @@ TraversalCode CSE_ValidityChecker::PreExpr(const Expr* e) {
|
||||||
// potentially executing &default functions. In either case,
|
// potentially executing &default functions. In either case,
|
||||||
// the type of the expression reflects the type we want to analyze
|
// the type of the expression reflects the type we want to analyze
|
||||||
// for side effects.
|
// for side effects.
|
||||||
if ( CheckRecordConstructor(e->GetType()) ) {
|
if ( CheckRecordConstructor(e->GetType()) )
|
||||||
is_valid = false;
|
|
||||||
return TC_ABORTALL;
|
return TC_ABORTALL;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXPR_INDEX:
|
case EXPR_INDEX:
|
||||||
|
@ -982,17 +970,13 @@ TraversalCode CSE_ValidityChecker::PreExpr(const Expr* e) {
|
||||||
if ( in_aggr_mod_stmt ) {
|
if ( in_aggr_mod_stmt ) {
|
||||||
auto aggr_id = aggr->AsNameExpr()->Id();
|
auto aggr_id = aggr->AsNameExpr()->Id();
|
||||||
|
|
||||||
if ( CheckID(aggr_id, true) || CheckAggrMod(aggr_t) ) {
|
if ( CheckID(aggr_id, true) || CheckAggrMod(aggr_t) )
|
||||||
is_valid = false;
|
|
||||||
return TC_ABORTALL;
|
return TC_ABORTALL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( t == EXPR_INDEX && aggr_t->Tag() == TYPE_TABLE ) {
|
else if ( t == EXPR_INDEX && aggr_t->Tag() == TYPE_TABLE ) {
|
||||||
if ( CheckTableRef(aggr_t) ) {
|
if ( CheckTableRef(aggr_t) )
|
||||||
is_valid = false;
|
|
||||||
return TC_ABORTALL;
|
return TC_ABORTALL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1004,7 +988,7 @@ TraversalCode CSE_ValidityChecker::PreExpr(const Expr* e) {
|
||||||
return TC_CONTINUE;
|
return TC_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSE_ValidityChecker::CheckID(const ID* id, bool ignore_orig) const {
|
bool CSE_ValidityChecker::CheckID(const ID* id, bool ignore_orig) {
|
||||||
// Only check type info for aggregates.
|
// Only check type info for aggregates.
|
||||||
auto id_t = IsAggr(id->GetType()) ? id->GetType() : nullptr;
|
auto id_t = IsAggr(id->GetType()) ? id->GetType() : nullptr;
|
||||||
|
|
||||||
|
@ -1013,39 +997,39 @@ bool CSE_ValidityChecker::CheckID(const ID* id, bool ignore_orig) const {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( id == i )
|
if ( id == i )
|
||||||
return true; // reassignment
|
return Invalid(); // reassignment
|
||||||
|
|
||||||
if ( id_t && same_type(id_t, i->GetType()) ) {
|
if ( id_t && same_type(id_t, i->GetType()) ) {
|
||||||
// Same-type aggregate.
|
// Same-type aggregate.
|
||||||
// if ( ! ignore_orig ) printf("identifier %s (%d), start %s, end %s\n", id->Name(), ignore_orig,
|
// if ( ! ignore_orig ) printf("identifier %s (%d), start %s, end %s\n", id->Name(), ignore_orig,
|
||||||
// obj_desc(start_e).c_str(), obj_desc(end_e).c_str());
|
// obj_desc(start_e).c_str(), obj_desc(end_e).c_str());
|
||||||
if ( ignore_orig )
|
if ( ignore_orig )
|
||||||
return true;
|
return Invalid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSE_ValidityChecker::CheckAggrMod(const TypePtr& t) const {
|
bool CSE_ValidityChecker::CheckAggrMod(const TypePtr& t) {
|
||||||
if ( ! IsAggr(t) )
|
if ( ! IsAggr(t) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for ( auto i : ids )
|
for ( auto i : ids )
|
||||||
if ( same_type(t, i->GetType()) )
|
if ( same_type(t, i->GetType()) )
|
||||||
return true;
|
return Invalid();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSE_ValidityChecker::CheckRecordConstructor(const TypePtr& t) const {
|
bool CSE_ValidityChecker::CheckRecordConstructor(const TypePtr& t) {
|
||||||
if ( t->Tag() != TYPE_RECORD )
|
if ( t->Tag() != TYPE_RECORD )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return CheckSideEffects(SideEffectsOp::CONSTRUCTION, t);
|
return CheckSideEffects(SideEffectsOp::CONSTRUCTION, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSE_ValidityChecker::CheckTableMod(const TypePtr& t) const {
|
bool CSE_ValidityChecker::CheckTableMod(const TypePtr& t) {
|
||||||
if ( ! CheckAggrMod(t) )
|
if ( ! CheckAggrMod(t) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1055,14 +1039,14 @@ bool CSE_ValidityChecker::CheckTableMod(const TypePtr& t) const {
|
||||||
return CheckSideEffects(SideEffectsOp::WRITE, t);
|
return CheckSideEffects(SideEffectsOp::WRITE, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSE_ValidityChecker::CheckTableRef(const TypePtr& t) const { return CheckSideEffects(SideEffectsOp::READ, t); }
|
bool CSE_ValidityChecker::CheckTableRef(const TypePtr& t) { return CheckSideEffects(SideEffectsOp::READ, t); }
|
||||||
|
|
||||||
bool CSE_ValidityChecker::CheckCall(const CallExpr* c) const {
|
bool CSE_ValidityChecker::CheckCall(const CallExpr* c) {
|
||||||
auto func = c->Func();
|
auto func = c->Func();
|
||||||
std::string desc;
|
std::string desc;
|
||||||
if ( func->Tag() != EXPR_NAME )
|
if ( func->Tag() != EXPR_NAME )
|
||||||
// Can't analyze indirect calls.
|
// Can't analyze indirect calls.
|
||||||
return true;
|
return Invalid();
|
||||||
|
|
||||||
IDSet non_local_ids;
|
IDSet non_local_ids;
|
||||||
TypeSet aggrs;
|
TypeSet aggrs;
|
||||||
|
@ -1071,20 +1055,30 @@ bool CSE_ValidityChecker::CheckCall(const CallExpr* c) const {
|
||||||
auto resolved = pfs.GetCallSideEffects(func->AsNameExpr(), non_local_ids, aggrs, is_unknown);
|
auto resolved = pfs.GetCallSideEffects(func->AsNameExpr(), non_local_ids, aggrs, is_unknown);
|
||||||
ASSERT(resolved);
|
ASSERT(resolved);
|
||||||
|
|
||||||
return is_unknown || CheckSideEffects(non_local_ids, aggrs);
|
if ( is_unknown || CheckSideEffects(non_local_ids, aggrs) )
|
||||||
|
return Invalid();
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSE_ValidityChecker::CheckSideEffects(SideEffectsOp::AccessType access, const TypePtr& t) const {
|
bool CSE_ValidityChecker::CheckSideEffects(SideEffectsOp::AccessType access, const TypePtr& t) {
|
||||||
IDSet non_local_ids;
|
IDSet non_local_ids;
|
||||||
TypeSet aggrs;
|
TypeSet aggrs;
|
||||||
|
|
||||||
if ( pfs.GetSideEffects(access, t.get(), non_local_ids, aggrs) )
|
// if ( access == SideEffectsOp::CONSTRUCTION ) printf("assessing construction\n");
|
||||||
return true;
|
|
||||||
|
if ( pfs.GetSideEffects(access, t.get(), non_local_ids, aggrs) ) {
|
||||||
|
// if ( access == SideEffectsOp::CONSTRUCTION ) printf("bailing directly on construction\n");
|
||||||
|
return Invalid();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if ( access == SideEffectsOp::CONSTRUCTION ) printf("construction has %ld/%ld non-locals/aggrs\n",
|
||||||
|
// non_local_ids.size(), aggrs.size());
|
||||||
|
|
||||||
return CheckSideEffects(non_local_ids, aggrs);
|
return CheckSideEffects(non_local_ids, aggrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSE_ValidityChecker::CheckSideEffects(const IDSet& non_local_ids, const TypeSet& aggrs) const {
|
bool CSE_ValidityChecker::CheckSideEffects(const IDSet& non_local_ids, const TypeSet& aggrs) {
|
||||||
if ( non_local_ids.empty() && aggrs.empty() )
|
if ( non_local_ids.empty() && aggrs.empty() )
|
||||||
// This is far and away the most common case.
|
// This is far and away the most common case.
|
||||||
return false;
|
return false;
|
||||||
|
@ -1092,12 +1086,14 @@ bool CSE_ValidityChecker::CheckSideEffects(const IDSet& non_local_ids, const Typ
|
||||||
for ( auto i : ids ) {
|
for ( auto i : ids ) {
|
||||||
for ( auto nli : non_local_ids )
|
for ( auto nli : non_local_ids )
|
||||||
if ( nli == i )
|
if ( nli == i )
|
||||||
return true;
|
return Invalid();
|
||||||
|
|
||||||
auto i_t = i->GetType();
|
auto i_t = i->GetType();
|
||||||
for ( auto a : aggrs )
|
for ( auto a : aggrs )
|
||||||
if ( same_type(a, i_t.get()) )
|
if ( same_type(a, i_t.get()) ) {
|
||||||
return true;
|
// printf("invalid identifier %s\n", i->Name());
|
||||||
|
return Invalid();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "zeek/Desc.h" // ###
|
||||||
#include "zeek/Expr.h"
|
#include "zeek/Expr.h"
|
||||||
#include "zeek/Scope.h"
|
#include "zeek/Scope.h"
|
||||||
#include "zeek/Stmt.h"
|
#include "zeek/Stmt.h"
|
||||||
|
@ -344,20 +345,25 @@ public:
|
||||||
protected:
|
protected:
|
||||||
// Returns true if an assignment involving the given identifier on
|
// Returns true if an assignment involving the given identifier on
|
||||||
// the LHS is in conflict with the identifiers we're tracking.
|
// the LHS is in conflict with the identifiers we're tracking.
|
||||||
bool CheckID(const ID* id, bool ignore_orig) const;
|
bool CheckID(const ID* id, bool ignore_orig);
|
||||||
|
|
||||||
// Returns true if a modification to an aggregate of the given type
|
// Returns true if a modification to an aggregate of the given type
|
||||||
// potentially aliases with one of the identifiers we're tracking.
|
// potentially aliases with one of the identifiers we're tracking.
|
||||||
bool CheckAggrMod(const TypePtr& t) const;
|
bool CheckAggrMod(const TypePtr& t);
|
||||||
|
|
||||||
// About elements ...
|
// About elements ...
|
||||||
// ###
|
// ###
|
||||||
bool CheckRecordConstructor(const TypePtr& t) const;
|
bool CheckRecordConstructor(const TypePtr& t);
|
||||||
bool CheckTableMod(const TypePtr& t) const;
|
bool CheckTableMod(const TypePtr& t);
|
||||||
bool CheckTableRef(const TypePtr& t) const;
|
bool CheckTableRef(const TypePtr& t);
|
||||||
bool CheckCall(const CallExpr* c) const;
|
bool CheckCall(const CallExpr* c);
|
||||||
bool CheckSideEffects(SideEffectsOp::AccessType access, const TypePtr& t) const;
|
bool CheckSideEffects(SideEffectsOp::AccessType access, const TypePtr& t);
|
||||||
bool CheckSideEffects(const IDSet& non_local_ids, const TypeSet& aggrs) const;
|
bool CheckSideEffects(const IDSet& non_local_ids, const TypeSet& aggrs);
|
||||||
|
|
||||||
|
bool Invalid() {
|
||||||
|
is_valid = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Profile across all script functions.
|
// Profile across all script functions.
|
||||||
ProfileFuncs& pfs;
|
ProfileFuncs& pfs;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue