zeek/src/StmtBase.h
Arne Welzel 171846a37a parse.y/directives: Reject directives as statements
Avoid the issue outlined in #2289 where the @if or @else is taken as the
statement of an `if`, `for` or `while` by rejecting such constructs.

Effectively this means the following scripts are now rejected:

    # Print's "cond true" with Zeek 5.0 even though the `if ( F )`
    # should be in effect.

    if ( F )
        @if ( T )
            print "cond true";
        @else
            print "cond false";
        @endif

or

    # Print's "hello" once with Zeek 5.0
    local v = vector( 1, 2, 3 );

    for ( i in v )
        @if ( T )
        print("hello")
        @endif

To make above work as intended, additional braces can be used.

    if ( T )
        {
    @if ( cond )
            print "cond true";
    @else
            print "cond false";
    @endif
        }

    for ( i in v )
        {
    @if ( T )
        print("hello")
    @endif
        }
2022-08-26 09:42:50 +02:00

220 lines
6.1 KiB
C++

// See the file "COPYING" in the main distribution directory for copyright.
#pragma once
// Base class for Zeek statements. We maintain it separately from
// the bulk of Stmt.h to allow Expr.h to include it, necessary for
// Expr.h to use StmtPtr.
#include "zeek/IntrusivePtr.h"
#include "zeek/Obj.h"
#include "zeek/StmtEnums.h"
#include "zeek/TraverseTypes.h"
#include "zeek/util.h"
namespace zeek
{
class Val;
using ValPtr = IntrusivePtr<Val>;
namespace run_state
{
extern double network_time;
}
namespace detail
{
class CompositeHash;
class Frame;
class CatchReturnStmt;
class ExprStmt;
class ForStmt;
class IfStmt;
class InitStmt;
class NullStmt;
class PrintStmt;
class ReturnStmt;
class StmtList;
class SwitchStmt;
class WhenStmt;
class WhileStmt;
class EventExpr;
class ListExpr;
using EventExprPtr = IntrusivePtr<EventExpr>;
using ListExprPtr = IntrusivePtr<ListExpr>;
class Inliner;
class Reducer;
class Stmt;
using StmtPtr = IntrusivePtr<Stmt>;
class StmtOptInfo;
class Stmt : public Obj
{
public:
StmtTag Tag() const { return tag; }
~Stmt() override;
virtual ValPtr Exec(Frame* f, StmtFlowType& flow) = 0;
Stmt* Ref()
{
zeek::Ref(this);
return this;
}
StmtPtr ThisPtr() { return {NewRef{}, this}; }
bool SetLocationInfo(const Location* loc) override { return Stmt::SetLocationInfo(loc, loc); }
bool SetLocationInfo(const Location* start, const Location* end) override;
// True if the statement has no side effects, false otherwise.
virtual bool IsPure() const;
StmtList* AsStmtList();
const StmtList* AsStmtList() const;
ForStmt* AsForStmt();
const ForStmt* AsForStmt() const;
const ExprStmt* AsExprStmt() const;
const PrintStmt* AsPrintStmt() const;
const InitStmt* AsInitStmt() const;
const CatchReturnStmt* AsCatchReturnStmt() const;
const ReturnStmt* AsReturnStmt() const;
const IfStmt* AsIfStmt() const;
const WhileStmt* AsWhileStmt() const;
const WhenStmt* AsWhenStmt() const;
const SwitchStmt* AsSwitchStmt() const;
const NullStmt* AsNullStmt() const;
void RegisterAccess() const
{
last_access = run_state::network_time;
access_count++;
}
void AccessStats(ODesc* d) const;
uint32_t GetAccessCount() const { return access_count; }
void Describe(ODesc* d) const final;
virtual void IncrBPCount() { ++breakpoint_count; }
virtual void DecrBPCount();
virtual unsigned int BPCount() const { return breakpoint_count; }
virtual TraversalCode Traverse(TraversalCallback* cb) const = 0;
// Returns a duplicate of the statement so that modifications
// can be made to statements from inlining function bodies - or
// to the originals - without affecting other instances.
//
// It's tempting to think that there are some statements that
// are safe to share across multiple functions and could just
// return references to themselves - but since we associate
// information for script optimization with individual statements
// nodes, even these need to be duplicated.
virtual StmtPtr Duplicate() = 0;
// Recursively traverses the AST to inline eligible function calls.
virtual void Inline(Inliner* inl) { }
// True if the statement is in reduced form.
virtual bool IsReduced(Reducer* c) const;
// Returns a reduced version of the statement, as managed by
// the given Reducer.
StmtPtr Reduce(Reducer* c);
virtual StmtPtr DoReduce(Reducer* c) { return ThisPtr(); }
// True if there's definitely no control flow past the statement.
// The argument governs whether to ignore "break" statements, given
// they mean two different things depending on whether they're in
// a loop or a switch. Also, if we want to know whether flow reaches
// the *end* of a loop, then we also want to ignore break's, as
// in that case, they do lead to flow reaching the end.
virtual bool NoFlowAfter(bool ignore_break) const { return false; }
// Access to the original statement from which this one is derived,
// or this one if we don't have an original. Returns a bare pointer
// rather than a StmtPtr to emphasize that the access is read-only.
const Stmt* Original() const { return original ? original->Original() : this; }
// Designate the given Stmt node as the original for this one.
void SetOriginal(StmtPtr _orig)
{
if ( ! original )
original = std::move(_orig);
}
// A convenience function for taking a newly-created Stmt,
// making it point to us as the successor, and returning it.
//
// Takes a Stmt* rather than a StmtPtr to de-clutter the calling
// code, which is always passing in "new XyzStmt(...)". This
// call, as a convenient side effect, transforms that bare pointer
// into a StmtPtr.
virtual StmtPtr SetSucc(Stmt* succ)
{
succ->SetOriginal({NewRef{}, this});
return {AdoptRef{}, succ};
}
const detail::Location* GetLocationInfo() const override
{
if ( original )
return original->GetLocationInfo();
else
return Obj::GetLocationInfo();
}
// Access script optimization information associated with
// this statement.
StmtOptInfo* GetOptInfo() const { return opt_info; }
// Returns the number of statements created since the last reset.
static int GetNumStmts() { return num_stmts; }
// Clears the number of statements created.
static void ResetNumStmts() { num_stmts = 0; }
protected:
explicit Stmt(StmtTag arg_tag);
// Helper function called after reductions to perform canonical
// actions.
StmtPtr TransformMe(StmtPtr new_me, Reducer* c);
void AddTag(ODesc* d) const;
virtual void StmtDescribe(ODesc* d) const;
void DescribeDone(ODesc* d) const;
StmtTag tag;
int breakpoint_count; // how many breakpoints on this statement
// FIXME: Learn the exact semantics of mutable.
mutable double last_access; // time of last execution
mutable uint32_t access_count; // number of executions
// The original statement from which this statement was
// derived, if any. Used as an aid for generating meaningful
// and correctly-localized error messages.
StmtPtr original = nullptr;
// Information associated with the Stmt for purposes of
// script optimization.
StmtOptInfo* opt_info;
// Number of statements created thus far.
static int num_stmts;
};
} // namespace detail
} // namespace zeek