From 3521a92a004020170dd79c79a7ad99d58eb9bd8a Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 22 Aug 2014 16:49:10 -0500 Subject: [PATCH] Detect functions that try to bind variables from an outer scope. And raise an error saying that's not supported. Addresses BIT-1233. --- src/Stmt.cc | 9 ++++- src/Var.cc | 39 +++++++++++++++++++ .../Baseline/language.outer_param_binding/out | 3 ++ .../btest/language/outer_param_binding.bro | 27 +++++++++++++ 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 testing/btest/Baseline/language.outer_param_binding/out create mode 100644 testing/btest/language/outer_param_binding.bro diff --git a/src/Stmt.cc b/src/Stmt.cc index 3571cad197..cb716b3f15 100644 --- a/src/Stmt.cc +++ b/src/Stmt.cc @@ -660,8 +660,13 @@ void Case::Describe(ODesc* d) const TraversalCode Case::Traverse(TraversalCallback* cb) const { - TraversalCode tc = cases->Traverse(cb); - HANDLE_TC_STMT_PRE(tc); + TraversalCode tc; + + if ( cases ) + { + tc = cases->Traverse(cb); + HANDLE_TC_STMT_PRE(tc); + } tc = s->Traverse(cb); HANDLE_TC_STMT_PRE(tc); diff --git a/src/Var.cc b/src/Var.cc index aa45faaf41..6cb113a11e 100644 --- a/src/Var.cc +++ b/src/Var.cc @@ -9,6 +9,7 @@ #include "Serializer.h" #include "RemoteSerializer.h" #include "EventRegistry.h" +#include "Traverse.h" static Val* init_val(Expr* init, const BroType* t, Val* aggr) { @@ -392,6 +393,34 @@ void begin_func(ID* id, const char* module_name, function_flavor flavor, } } +class OuterParamBindingFinder : public TraversalCallback { +public: + OuterParamBindingFinder(Scope* s) + : scope(s) { } + + virtual TraversalCode PreExpr(const Expr*); + + Scope* scope; + vector outer_param_references; +}; + +TraversalCode OuterParamBindingFinder::PreExpr(const Expr* expr) + { + if ( expr->Tag() != EXPR_NAME ) + return TC_CONTINUE; + + const NameExpr* e = static_cast(expr); + + if ( e->Id()->IsGlobal() ) + return TC_CONTINUE; + + if ( scope->GetIDs()->Lookup(e->Id()->Name()) ) + return TC_CONTINUE; + + outer_param_references.push_back(e); + return TC_CONTINUE; + } + void end_func(Stmt* body, attr_list* attrs) { int frame_size = current_scope()->Length(); @@ -429,6 +458,16 @@ void end_func(Stmt* body, attr_list* attrs) } } + if ( streq(id->Name(), "anonymous-function") ) + { + OuterParamBindingFinder cb(scope); + body->Traverse(&cb); + + for ( size_t i = 0; i < cb.outer_param_references.size(); ++i ) + cb.outer_param_references[i]->Error( + "referencing outer function parameters not supported"); + } + if ( id->HasVal() ) id->ID_Val()->AsFunc()->AddBody(body, inits, frame_size, priority); else diff --git a/testing/btest/Baseline/language.outer_param_binding/out b/testing/btest/Baseline/language.outer_param_binding/out new file mode 100644 index 0000000000..3dfc82da3e --- /dev/null +++ b/testing/btest/Baseline/language.outer_param_binding/out @@ -0,0 +1,3 @@ +error in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.outer_param_binding/outer_param_binding.bro, line 16: referencing outer function parameters not supported (c) +error in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.outer_param_binding/outer_param_binding.bro, line 16: referencing outer function parameters not supported (d) +error in /Users/jsiwek/Projects/bro/bro/testing/btest/.tmp/language.outer_param_binding/outer_param_binding.bro, line 17: referencing outer function parameters not supported (b) diff --git a/testing/btest/language/outer_param_binding.bro b/testing/btest/language/outer_param_binding.bro new file mode 100644 index 0000000000..fb37fd4712 --- /dev/null +++ b/testing/btest/language/outer_param_binding.bro @@ -0,0 +1,27 @@ +# @TEST-EXEC-FAIL: bro -b %INPUT >out 2>&1 +# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out + +type Foo: record { + x: function(a: string) : string; +}; + +function bar(b: string, c: string) + { + local f: Foo; + local d = 8; + f = [$x=function(a: string) : string + { + local x = 0; + print x; + print c, d; + return cat(a, " ", b); + } + ]; + + print f$x("2"); + } + +event bro_init() + { + bar("1", "20"); + }