GH-725: fix logic for finding a lambda's usage of outer IDs

This commit is contained in:
Jon Siwek 2020-03-26 17:05:59 -07:00
parent f032885085
commit 1ca11f11c7
6 changed files with 43 additions and 22 deletions

View file

@ -4366,6 +4366,11 @@ LambdaExpr::LambdaExpr(std::unique_ptr<function_ingredients> arg_ing,
id->SetConst(); id->SetConst();
} }
Scope* LambdaExpr::GetScope() const
{
return ingredients->scope.get();
}
IntrusivePtr<Val> LambdaExpr::Eval(Frame* f) const IntrusivePtr<Val> LambdaExpr::Eval(Frame* f) const
{ {
auto lamb = make_intrusive<BroFunc>( auto lamb = make_intrusive<BroFunc>(

View file

@ -61,6 +61,7 @@ extern const char* expr_name(BroExprTag t);
template <class T> class IntrusivePtr; template <class T> class IntrusivePtr;
class Stmt; class Stmt;
class Frame; class Frame;
class Scope;
class ListExpr; class ListExpr;
class NameExpr; class NameExpr;
class IndexExpr; class IndexExpr;
@ -813,6 +814,8 @@ public:
IntrusivePtr<Val> Eval(Frame* f) const override; IntrusivePtr<Val> Eval(Frame* f) const override;
TraversalCode Traverse(TraversalCallback* cb) const override; TraversalCode Traverse(TraversalCallback* cb) const override;
Scope* GetScope() const;
protected: protected:
void ExprDescribe(ODesc* d) const override; void ExprDescribe(ODesc* d) const override;

View file

@ -12,7 +12,6 @@
#include "Scope.h" #include "Scope.h"
#include "Type.h" #include "Type.h"
#include "File.h" #include "File.h"
#include "Scope.h"
#include "Traverse.h" #include "Traverse.h"
#include "Val.h" #include "Val.h"
#include "zeekygen/Manager.h" #include "zeekygen/Manager.h"

View file

@ -419,32 +419,25 @@ void begin_func(ID* id, const char* module_name, function_flavor flavor,
class OuterIDBindingFinder : public TraversalCallback { class OuterIDBindingFinder : public TraversalCallback {
public: public:
OuterIDBindingFinder(Scope* s) OuterIDBindingFinder(Scope* s)
: scope(s) { } {
scopes.emplace_back(s);
}
virtual TraversalCode PreExpr(const Expr*); virtual TraversalCode PreExpr(const Expr*);
virtual TraversalCode PostExpr(const Expr*); virtual TraversalCode PostExpr(const Expr*);
Scope* scope; std::vector<Scope*> scopes;
vector<const NameExpr*> outer_id_references; vector<const NameExpr*> outer_id_references;
int lambda_depth = 0;
// Note: think we really ought to toggle this to false to prevent
// considering locals within inner-lambdas as "outer", but other logic
// for "selective cloning" and locating IDs in the closure chain may
// depend on current behavior and also needs to be changed.
bool search_inner_lambdas = true;
}; };
TraversalCode OuterIDBindingFinder::PreExpr(const Expr* expr) TraversalCode OuterIDBindingFinder::PreExpr(const Expr* expr)
{ {
if ( expr->Tag() == EXPR_LAMBDA ) if ( expr->Tag() == EXPR_LAMBDA )
++lambda_depth; {
auto le = static_cast<const LambdaExpr*>(expr);
if ( lambda_depth > 0 && ! search_inner_lambdas ) scopes.emplace_back(le->GetScope());
// Don't inspect the bodies of inner lambdas as they will have their
// own traversal to find outer IDs and we don't want to detect
// references to local IDs inside and accidentally treat them as
// "outer" since they can't be found in current scope.
return TC_CONTINUE; return TC_CONTINUE;
}
if ( expr->Tag() != EXPR_NAME ) if ( expr->Tag() != EXPR_NAME )
return TC_CONTINUE; return TC_CONTINUE;
@ -454,7 +447,10 @@ TraversalCode OuterIDBindingFinder::PreExpr(const Expr* expr)
if ( e->Id()->IsGlobal() ) if ( e->Id()->IsGlobal() )
return TC_CONTINUE; return TC_CONTINUE;
for ( const auto& scope : scopes )
if ( scope->Lookup(e->Id()->Name()) ) if ( scope->Lookup(e->Id()->Name()) )
// Shadowing is not allowed, so if it's found at inner scope, it's
// not something we have to worry about also being at outer scope.
return TC_CONTINUE; return TC_CONTINUE;
outer_id_references.push_back(e); outer_id_references.push_back(e);
@ -464,10 +460,7 @@ TraversalCode OuterIDBindingFinder::PreExpr(const Expr* expr)
TraversalCode OuterIDBindingFinder::PostExpr(const Expr* expr) TraversalCode OuterIDBindingFinder::PostExpr(const Expr* expr)
{ {
if ( expr->Tag() == EXPR_LAMBDA ) if ( expr->Tag() == EXPR_LAMBDA )
{ scopes.pop_back();
--lambda_depth;
assert(lambda_depth >= 0);
}
return TC_CONTINUE; return TC_CONTINUE;
} }

View file

@ -0,0 +1,2 @@
106
106

View file

@ -0,0 +1,19 @@
# @TEST-EXEC: zeek -b %INPUT >out
# @TEST-EXEC: btest-diff out
local outer = 100;
local lambda = function()
{
local inner = function(a: count, b: count, c: count, d: count, e: count, f: count)
{
print outer + f;
};
inner(1, 2, 3, 4, 5, 6);
};
lambda();
local copyLambda = copy(copy(copy(lambda)));
copyLambda();