mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
parse.y: Traverse AST post parsing to detect break/next usage issues
Seemed easiest to do it via the traversal infrastructure as we do not otherwise track enough context/scope when instantiating break or next statements. Might be worth moving this out of src/parse.y, but didn't exactly know where. Or maybe we wait until there's more such trivial validations popping up Fixes #2440
This commit is contained in:
parent
2ed42ef771
commit
850aaaa5a8
15 changed files with 227 additions and 2 deletions
97
src/ScriptValidation.cc
Normal file
97
src/ScriptValidation.cc
Normal file
|
@ -0,0 +1,97 @@
|
|||
#include "zeek/ScriptValidation.h"
|
||||
|
||||
#include "zeek/Func.h"
|
||||
#include "zeek/Reporter.h"
|
||||
#include "zeek/Stmt.h"
|
||||
#include "zeek/Traverse.h"
|
||||
|
||||
namespace zeek::detail
|
||||
{
|
||||
|
||||
// Validate context of break and next statement usage.
|
||||
class BreakNextScriptValidation : public TraversalCallback
|
||||
{
|
||||
public:
|
||||
TraversalCode PreStmt(const Stmt* stmt)
|
||||
{
|
||||
if ( ! StmtIsRelevant(stmt) )
|
||||
return TC_CONTINUE;
|
||||
|
||||
stmt_depths[stmt->Tag()] += 1;
|
||||
|
||||
if ( stmt->Tag() == STMT_BREAK && ! BreakStmtIsValid() )
|
||||
{
|
||||
zeek::reporter->PushLocation(stmt->GetLocationInfo());
|
||||
zeek::reporter->Error("break statement used outside of for, while or "
|
||||
"switch statement and not within a hook");
|
||||
zeek::reporter->PopLocation();
|
||||
}
|
||||
|
||||
if ( stmt->Tag() == STMT_NEXT && ! NextStmtIsValid() )
|
||||
{
|
||||
zeek::reporter->PushLocation(stmt->GetLocationInfo());
|
||||
zeek::reporter->Error("next statement used outside of for or while statement");
|
||||
zeek::reporter->PopLocation();
|
||||
}
|
||||
|
||||
return TC_CONTINUE;
|
||||
}
|
||||
|
||||
TraversalCode PostStmt(const Stmt* stmt)
|
||||
{
|
||||
if ( ! StmtIsRelevant(stmt) )
|
||||
return TC_CONTINUE;
|
||||
|
||||
--stmt_depths[stmt->Tag()];
|
||||
|
||||
assert(stmt_depths[stmt->Tag()] >= 0);
|
||||
|
||||
return TC_CONTINUE;
|
||||
}
|
||||
|
||||
TraversalCode PreFunction(const zeek::Func* func)
|
||||
{
|
||||
if ( func->Flavor() == zeek::FUNC_FLAVOR_HOOK )
|
||||
++hook_depth;
|
||||
|
||||
assert(hook_depth <= 1);
|
||||
|
||||
return TC_CONTINUE;
|
||||
}
|
||||
|
||||
TraversalCode PostFunction(const zeek::Func* func)
|
||||
{
|
||||
if ( func->Flavor() == zeek::FUNC_FLAVOR_HOOK )
|
||||
--hook_depth;
|
||||
|
||||
assert(hook_depth >= 0);
|
||||
|
||||
return TC_CONTINUE;
|
||||
}
|
||||
|
||||
private:
|
||||
bool StmtIsRelevant(const Stmt* stmt)
|
||||
{
|
||||
StmtTag tag = stmt->Tag();
|
||||
return tag == STMT_FOR || tag == STMT_WHILE || tag == STMT_SWITCH || tag == STMT_BREAK ||
|
||||
tag == STMT_NEXT;
|
||||
}
|
||||
|
||||
bool BreakStmtIsValid()
|
||||
{
|
||||
return hook_depth > 0 || stmt_depths[STMT_FOR] > 0 || stmt_depths[STMT_WHILE] > 0 ||
|
||||
stmt_depths[STMT_SWITCH] > 0;
|
||||
}
|
||||
|
||||
bool NextStmtIsValid() { return stmt_depths[STMT_FOR] > 0 || stmt_depths[STMT_WHILE] > 0; }
|
||||
|
||||
std::unordered_map<const StmtTag, int> stmt_depths;
|
||||
int hook_depth = 0;
|
||||
};
|
||||
|
||||
void script_validation()
|
||||
{
|
||||
zeek::detail::BreakNextScriptValidation bn_cb;
|
||||
zeek::detail::traverse_all(&bn_cb);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue