// See the file "COPYING" in the main distribution directory for copyright. #pragma once #include #include #include #include #include #include #include #include #include "BroList.h" #include "Obj.h" #include "IntrusivePtr.h" #include "Type.h" /* for function_flavor */ #include "TraverseTypes.h" #include "ZeekArgs.h" class Val; class ListExpr; class FuncType; class Stmt; class Frame; class ID; class CallExpr; class Scope; class Func : public BroObj { public: enum Kind { BRO_FUNC, BUILTIN_FUNC }; explicit Func(Kind arg_kind); ~Func() override; virtual bool IsPure() const = 0; function_flavor Flavor() const { return GetType()->Flavor(); } struct Body { IntrusivePtr stmts; int priority; bool operator<(const Body& other) const { return priority > other.priority; } // reverse sort }; const std::vector& GetBodies() const { return bodies; } bool HasBodies() const { return bodies.size(); } [[deprecated("Remove in v4.1. Use zeek::Args overload instead.")]] virtual IntrusivePtr Call(val_list* args, Frame* parent = nullptr) const; /** * Calls a Zeek function. * @param args the list of arguments to the function call. * @param parent the frame from which the function is being called. * @return the return value of the function call. */ virtual IntrusivePtr Call(const zeek::Args& args, Frame* parent = nullptr) const = 0; /** * A version of Call() taking a variable number of individual arguments. */ template std::enable_if_t< std::is_convertible_v>, IntrusivePtr>, IntrusivePtr> Call(Args&&... args) const { return Call(zeek::Args{std::forward(args)...}); } // Add a new event handler to an existing function (event). virtual void AddBody(IntrusivePtr new_body, id_list* new_inits, size_t new_frame_size, int priority = 0); virtual void SetScope(IntrusivePtr newscope); virtual Scope* GetScope() const { return scope.get(); } [[deprecated("Remove in v4.1. Use GetType().")]] virtual FuncType* FType() const { return type.get(); } const IntrusivePtr& GetType() const { return type; } Kind GetKind() const { return kind; } const char* Name() const { return name.c_str(); } void SetName(const char* arg_name) { name = arg_name; } void Describe(ODesc* d) const override = 0; virtual void DescribeDebug(ODesc* d, const zeek::Args* args) const; virtual IntrusivePtr DoClone(); virtual TraversalCode Traverse(TraversalCallback* cb) const; uint32_t GetUniqueFuncID() const { return unique_id; } static const IntrusivePtr& GetFuncPtrByID(uint32_t id) { static IntrusivePtr nil; return id >= unique_ids.size() ? nil : unique_ids[id]; } protected: Func(); // Copies this function's state into other. void CopyStateInto(Func* other) const; // Helper function for handling result of plugin hook. std::pair HandlePluginResult(std::pair plugin_result, function_flavor flavor) const; std::vector bodies; IntrusivePtr scope; Kind kind; uint32_t unique_id; IntrusivePtr type; std::string name; static inline std::vector> unique_ids; }; class BroFunc final : public Func { public: BroFunc(ID* id, IntrusivePtr body, id_list* inits, size_t frame_size, int priority); ~BroFunc() override; bool IsPure() const override; IntrusivePtr Call(const zeek::Args& args, Frame* parent) const override; /** * Adds adds a closure to the function. Closures are cloned and * future calls to BroFunc methods will not modify *f*. * * @param ids IDs that are captured by the closure. * @param f the closure to be captured. */ void AddClosure(id_list ids, Frame* f); /** * Replaces the current closure with one built from *data* * * @param data a serialized closure */ bool UpdateClosure(const broker::vector& data); /** * If the function's closure is a weak reference to the given frame, * upgrade to a strong reference of a shallow clone of that frame. */ bool StrengthenClosureReference(Frame* f); /** * Serializes this function's closure. * * @return a serialized version of the function's closure. */ broker::expected SerializeClosure() const; void AddBody(IntrusivePtr new_body, id_list* new_inits, size_t new_frame_size, int priority) override; /** Sets this function's outer_id list. */ void SetOuterIDs(id_list ids) { outer_ids = std::move(ids); } void Describe(ODesc* d) const override; protected: BroFunc() : Func(BRO_FUNC) {} IntrusivePtr AddInits(IntrusivePtr body, id_list* inits); /** * Clones this function along with its closures. */ IntrusivePtr DoClone() override; /** * Performs a selective clone of *f* using the IDs that were * captured in the function's closure. * * @param f the frame to be cloned. */ void SetClosureFrame(Frame* f); private: size_t frame_size; // List of the outer IDs used in the function. id_list outer_ids; // The frame the BroFunc was initialized in. Frame* closure = nullptr; bool weak_closure_ref = false; }; /** * A simple wrapper class to use for the return value of BIFs so that * they may return either a Val* or IntrusivePtr (the former could * potentially be deprecated). */ class BifReturnVal { public: template BifReturnVal(IntrusivePtr v) noexcept : rval(AdoptRef{}, v.release()) { } BifReturnVal(std::nullptr_t) noexcept; [[deprecated("Remove in v4.1. Return an IntrusivePtr instead.")]] BifReturnVal(Val* v) noexcept; IntrusivePtr rval; }; using built_in_func = BifReturnVal (*)(Frame* frame, const zeek::Args* args); class BuiltinFunc final : public Func { public: BuiltinFunc(built_in_func func, const char* name, bool is_pure); ~BuiltinFunc() override; bool IsPure() const override; IntrusivePtr Call(const zeek::Args& args, Frame* parent) const override; built_in_func TheFunc() const { return func; } void Describe(ODesc* d) const override; protected: BuiltinFunc() { func = nullptr; is_pure = 0; } built_in_func func; bool is_pure; }; extern void builtin_error(const char* msg); extern void builtin_error(const char* msg, IntrusivePtr); extern void builtin_error(const char* msg, BroObj* arg); extern void init_builtin_funcs(); extern void init_builtin_funcs_subdirs(); extern bool check_built_in_call(BuiltinFunc* f, CallExpr* call); struct CallInfo { const CallExpr* call; const Func* func; const zeek::Args& args; }; // Struct that collects all the specifics defining a Func. Used for BroFuncs // with closures. struct function_ingredients { // Gathers all of the information from a scope and a function body needed // to build a function. function_ingredients(IntrusivePtr scope, IntrusivePtr body); ~function_ingredients(); IntrusivePtr id; IntrusivePtr body; id_list* inits; int frame_size; int priority; IntrusivePtr scope; }; extern std::vector call_stack; extern std::string render_call_stack(); // This is set to true after the built-in functions have been initialized. extern bool did_builtin_init;