diff --git a/CHANGES b/CHANGES index 76b13f3617..78b6f1bffd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +4.2.0-dev.514 | 2022-01-03 13:56:12 -0700 + + * deprecation warning on use of out-of-scope local (Vern Paxson, Corelight) + 4.2.0-dev.510 | 2022-01-03 13:54:52 -0700 * Switch BitTorrent analyzer to Zeek's regex engine (Avinal Kumar) diff --git a/NEWS b/NEWS index bca990b9b9..f40bec8061 100644 --- a/NEWS +++ b/NEWS @@ -177,6 +177,27 @@ Deprecated Functionality replaced by ``analyzer_confirmation`` and ``analyzer_violation`` which can also now be implemented in packet analyzers. +- Declaring a local variable in an inner scope and then accessing it in an + outer scope is now deprecated. For example, + + if ( foo() ) + { + local a = 5; + ... + } + print a; + + is deprecated. You can address the issue by hoisting the declaration + to the outer scope, such as: + + local a: count; + if ( foo() ) + { + a = 5; + ... + } + print a; + Zeek 4.1.0 ========== diff --git a/VERSION b/VERSION index de438350df..a6cc3219f2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.2.0-dev.510 +4.2.0-dev.514 diff --git a/src/parse.y b/src/parse.y index cf60ff58ac..f86da73ccc 100644 --- a/src/parse.y +++ b/src/parse.y @@ -142,6 +142,10 @@ bool resolving_global_ID = false; bool defining_global_ID = false; std::vector saved_in_init; +std::vector> locals_at_this_scope; +static std::unordered_set out_of_scope_locals; +static std::unordered_set warned_about_locals; + static Location func_hdr_location; static int func_hdr_cond_epoch = 0; EnumType* cur_enum_type = nullptr; @@ -557,6 +561,8 @@ expr: | TOK_LOCAL local_id '=' expr { set_location(@2, @4); + if ( ! locals_at_this_scope.empty() ) + locals_at_this_scope.back().insert($2); $$ = add_and_assign_local({AdoptRef{}, $2}, {AdoptRef{}, $4}, val_mgr->True()).release(); } @@ -797,6 +803,14 @@ expr: } else { + if ( out_of_scope_locals.count(id.get()) > 0 && + warned_about_locals.count(id.get()) == 0 ) + { + // Remove in v5.1 + reporter->Warning("use of out-of-scope local %s deprecated; move declaration to outer scope", id->Name()); + warned_about_locals.insert(id.get()); + } + $$ = new NameExpr(std::move(id)); } } @@ -1298,6 +1312,10 @@ func_body: { saved_in_init.push_back(in_init); in_init = 0; + + locals_at_this_scope.clear(); + out_of_scope_locals.clear(); + warned_about_locals.clear(); } stmt_list @@ -1573,11 +1591,20 @@ attr: ; stmt: - '{' opt_no_test_block stmt_list '}' + '{' { - set_location(@1, @4); - $$ = $3; - if ( $2 ) + std::set id_set; + locals_at_this_scope.emplace_back(id_set); + } + opt_no_test_block stmt_list '}' + { + auto& scope_locals = locals_at_this_scope.back(); + out_of_scope_locals.insert(scope_locals.begin(), scope_locals.end()); + locals_at_this_scope.pop_back(); + + set_location(@1, @5); + $$ = $4; + if ( $3 ) script_coverage_mgr.DecIgnoreDepth(); } @@ -1684,6 +1711,8 @@ stmt: | TOK_LOCAL local_id opt_type init_class opt_init opt_attr ';' opt_no_test { set_location(@1, @7); + if ( ! locals_at_this_scope.empty() ) + locals_at_this_scope.back().insert($2); $$ = build_local($2, $3, $4, $5, $6, VAR_REGULAR, ! $8).release(); } diff --git a/testing/btest/Baseline/language.uninitialized-local2/err b/testing/btest/Baseline/language.uninitialized-local2/err index b7c6377f7b..ad64116f3d 100644 --- a/testing/btest/Baseline/language.uninitialized-local2/err +++ b/testing/btest/Baseline/language.uninitialized-local2/err @@ -1,2 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +warning in <...>/uninitialized-local2.zeek, line 23: use of out-of-scope local var_b deprecated; move declaration to outer scope expression error in <...>/uninitialized-local2.zeek, line 23: value used but not set (var_b)