mirror of
https://github.com/zeek/zeek.git
synced 2025-10-08 17:48:21 +00:00
GH-927: Fix circumvention of evaluation order in 'when' conditions
Historically, a 'when' condition performed an AST-traversal to locate any index-expressions like `x[9]` and evaluated them so that it could register the associated value as something for which it needs to receive "modification" notifications. Evaluating arbitrary expressions during an AST-traversal like that ignores the typical order-of-evaluation/short-circuiting you'd expect if the condition was evaluated normally, from its root expression. Now, a new subclass of IndexExpr is used to keep track of all IndexExpr results in the context of evaluating a 'when' condition without having to do a secondary AST-traversal-and-eval. i.e. the first evaluation of the full 'when' condition follows the typical expression-evaluation semantics (as always), but additionally now captures all the values a Trigger needs to monitor for modifications.
This commit is contained in:
parent
0771dbcec6
commit
33ca675515
6 changed files with 141 additions and 29 deletions
|
@ -56,24 +56,6 @@ TraversalCode trigger::TriggerTraversalCallback::PreExpr(const Expr* expr)
|
|||
break;
|
||||
};
|
||||
|
||||
case EXPR_INDEX:
|
||||
{
|
||||
const auto* e = static_cast<const IndexExpr*>(expr);
|
||||
Obj::SuppressErrors no_errors;
|
||||
|
||||
try
|
||||
{
|
||||
auto v = e->Eval(trigger->frame);
|
||||
|
||||
if ( v )
|
||||
trigger->Register(v.get());
|
||||
}
|
||||
catch ( InterpreterException& )
|
||||
{ /* Already reported */ }
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// All others are uninteresting.
|
||||
break;
|
||||
|
@ -217,12 +199,15 @@ Trigger::~Trigger()
|
|||
// point.
|
||||
}
|
||||
|
||||
void Trigger::Init()
|
||||
void Trigger::Init(std::vector<ValPtr> index_expr_results)
|
||||
{
|
||||
assert(! disabled);
|
||||
UnregisterAll();
|
||||
TriggerTraversalCallback cb(this);
|
||||
cond->Traverse(&cb);
|
||||
|
||||
for ( const auto& v : index_expr_results )
|
||||
Register(v.get());
|
||||
}
|
||||
|
||||
bool Trigger::Eval()
|
||||
|
@ -265,6 +250,7 @@ bool Trigger::Eval()
|
|||
f->SetTrigger({NewRef{}, this});
|
||||
|
||||
ValPtr v;
|
||||
IndexExprWhen::StartEval();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -273,6 +259,9 @@ bool Trigger::Eval()
|
|||
catch ( InterpreterException& )
|
||||
{ /* Already reported */ }
|
||||
|
||||
IndexExprWhen::EndEval();
|
||||
auto index_expr_results = IndexExprWhen::TakeAllResults();
|
||||
|
||||
f->ClearTrigger();
|
||||
|
||||
if ( f->HasDelayed() )
|
||||
|
@ -288,7 +277,7 @@ bool Trigger::Eval()
|
|||
// Not true. Perhaps next time...
|
||||
DBG_LOG(DBG_NOTIFIERS, "%s: trigger condition is false", Name());
|
||||
Unref(f);
|
||||
Init();
|
||||
Init(std::move(index_expr_results));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue