mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Merge remote-tracking branch 'origin/topic/jsiwek/alternate-hook-event-prototypes'
* origin/topic/jsiwek/alternate-hook-event-prototypes: Add warning for ineffective &default arguments in handlers Fix frame size allocation of alternate event/hook handlers Emit error for alternate event/hook prototype args with attributes Improve alternate event/hook prototype matching Allow alternate event/hook prototype declarations
This commit is contained in:
commit
ba1c03188f
24 changed files with 715 additions and 16 deletions
62
CHANGES
62
CHANGES
|
@ -1,4 +1,66 @@
|
||||||
|
|
||||||
|
3.2.0-dev.391 | 2020-04-13 14:59:50 -0700
|
||||||
|
|
||||||
|
* Add warning for ineffective &default arguments in handlers
|
||||||
|
|
||||||
|
For event/hook handlers that had a previous declaration, any &default
|
||||||
|
arguments are ineffective. Only &default uses in the initial
|
||||||
|
prototype's arguments have an effect (that includes if the handler
|
||||||
|
is actually the site at which the declaration occurs). (Jon Siwek, Corelight)
|
||||||
|
|
||||||
|
* Fix frame size allocation of alternate event/hook handlers
|
||||||
|
|
||||||
|
When the only existing handler doesn't use the full argument list, still
|
||||||
|
have to ensure the full frame is allocated because all arguments get set
|
||||||
|
regardless. (Jon Siwek, Corelight)
|
||||||
|
|
||||||
|
* Emit error for alternate event/hook prototype args with attributes
|
||||||
|
|
||||||
|
Argument attributes are only allowed in the canonical prototype. (Jon Siwek, Corelight)
|
||||||
|
|
||||||
|
* Improve alternate event/hook prototype matching
|
||||||
|
|
||||||
|
This fixes it to again allow the old behavior of matching a handler
|
||||||
|
against the canonical prototype as long as all argument types, but not
|
||||||
|
necessarily names, match. (Jon Siwek, Corelight)
|
||||||
|
|
||||||
|
* Allow alternate event/hook prototype declarations
|
||||||
|
|
||||||
|
The alternates must be some subset of the canonical prototype (the one
|
||||||
|
that's first declared) and allows users to define handlers for any
|
||||||
|
such prototype. Example:
|
||||||
|
|
||||||
|
# Prototype declarations
|
||||||
|
global my_event: event(s: string, c: count);
|
||||||
|
global my_event: event(c: count);
|
||||||
|
global my_event: event();
|
||||||
|
|
||||||
|
# Handler definitions
|
||||||
|
event my_event(s: string, c: count) { print s, c; }
|
||||||
|
event my_event(c: count) { print c; }
|
||||||
|
event my_event() { }
|
||||||
|
|
||||||
|
This allows handlers to consume a subset of the arguments or even
|
||||||
|
re-order them. This makes it easier to either extend an existing
|
||||||
|
event/hook's arguments and/or deprecate usages of certain prototypes. (Jon Siwek, Corelight)
|
||||||
|
|
||||||
|
* Fix Broker topics used to uniquely identify cluster nodes
|
||||||
|
|
||||||
|
Node-specific topic prefix subscriptions/publications now add a trailing
|
||||||
|
slash like "zeek/cluster/node/<name>/". Without the trailing slash,
|
||||||
|
messages attempting to target "proxy-10" may also be sent to "proxy-1"
|
||||||
|
since subscription matching is prefix-based. (Jon Siwek, Corelight)
|
||||||
|
|
||||||
|
* Update submodule(s)
|
||||||
|
|
||||||
|
[nomail] (Jon Siwek, Corelight)
|
||||||
|
|
||||||
|
* Fix include in X509Common.h
|
||||||
|
|
||||||
|
Give full path to Analyzer.h, so that X509Common.h is include-able by
|
||||||
|
plugins. (Johanna Amann, Corelight)
|
||||||
|
|
||||||
|
|
||||||
3.2.0-dev.382 | 2020-04-09 13:17:03 -0700
|
3.2.0-dev.382 | 2020-04-09 13:17:03 -0700
|
||||||
|
|
||||||
* Remove 'using namespace std' as well as other using statements from headers.
|
* Remove 'using namespace std' as well as other using statements from headers.
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
3.2.0-dev.382
|
3.2.0-dev.391
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 69d7443794e8712344561a49517340aab3e58ff4
|
Subproject commit abfe5cb864a17b8c06c70d4674b32a51280ee62b
|
2
doc
2
doc
|
@ -1 +1 @@
|
||||||
Subproject commit 23327f87955b382729db1419ba8e75feba038c05
|
Subproject commit fe6fe81c1524bb2d41b1d1d2fa80177e1437e501
|
|
@ -28,7 +28,7 @@ event rule_expire(r: Rule, p: PluginState) &priority=-5
|
||||||
rule_expire_impl(r, p);
|
rule_expire_impl(r, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
event rule_exists(r: Rule, p: PluginState, msg: string &default="") &priority=5
|
event rule_exists(r: Rule, p: PluginState, msg: string) &priority=5
|
||||||
{
|
{
|
||||||
rule_added_impl(r, p, T, msg);
|
rule_added_impl(r, p, T, msg);
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ event rule_exists(r: Rule, p: PluginState, msg: string &default="") &priority=5
|
||||||
schedule r$expire { rule_expire(r, p) };
|
schedule r$expire { rule_expire(r, p) };
|
||||||
}
|
}
|
||||||
|
|
||||||
event rule_added(r: Rule, p: PluginState, msg: string &default="") &priority=5
|
event rule_added(r: Rule, p: PluginState, msg: string) &priority=5
|
||||||
{
|
{
|
||||||
rule_added_impl(r, p, F, msg);
|
rule_added_impl(r, p, F, msg);
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ event rule_added(r: Rule, p: PluginState, msg: string &default="") &priority=5
|
||||||
schedule r$expire { rule_expire(r, p) };
|
schedule r$expire { rule_expire(r, p) };
|
||||||
}
|
}
|
||||||
|
|
||||||
event rule_removed(r: Rule, p: PluginState, msg: string &default="") &priority=-5
|
event rule_removed(r: Rule, p: PluginState, msg: string) &priority=-5
|
||||||
{
|
{
|
||||||
rule_removed_impl(r, p, msg);
|
rule_removed_impl(r, p, msg);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ event rule_timeout(r: Rule, i: FlowInfo, p: PluginState) &priority=-5
|
||||||
rule_timeout_impl(r, i, p);
|
rule_timeout_impl(r, i, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
event rule_error(r: Rule, p: PluginState, msg: string &default="") &priority=-5
|
event rule_error(r: Rule, p: PluginState, msg: string) &priority=-5
|
||||||
{
|
{
|
||||||
rule_error_impl(r, p, msg);
|
rule_error_impl(r, p, msg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,7 +259,7 @@ function cr_check_rule(r: Rule): bool
|
||||||
|
|
||||||
@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) )
|
@if ( ! Cluster::is_enabled() || ( Cluster::is_enabled() && Cluster::local_node_type() == Cluster::MANAGER ) )
|
||||||
|
|
||||||
event rule_added(r: Rule, p: PluginState, msg: string &default="")
|
event rule_added(r: Rule, p: PluginState, msg: string)
|
||||||
{
|
{
|
||||||
if ( !cr_check_rule(r) )
|
if ( !cr_check_rule(r) )
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -449,6 +449,11 @@ void BroFunc::AddBody(IntrusivePtr<Stmt> new_body, id_list* new_inits,
|
||||||
if ( new_frame_size > frame_size )
|
if ( new_frame_size > frame_size )
|
||||||
frame_size = new_frame_size;
|
frame_size = new_frame_size;
|
||||||
|
|
||||||
|
auto num_args = FType()->Args()->NumFields();
|
||||||
|
|
||||||
|
if ( num_args > static_cast<int>(frame_size) )
|
||||||
|
frame_size = num_args;
|
||||||
|
|
||||||
new_body = AddInits(std::move(new_body), new_inits);
|
new_body = AddInits(std::move(new_body), new_inits);
|
||||||
|
|
||||||
if ( Flavor() == FUNC_FLAVOR_FUNCTION )
|
if ( Flavor() == FUNC_FLAVOR_FUNCTION )
|
||||||
|
|
34
src/ID.cc
34
src/ID.cc
|
@ -431,8 +431,42 @@ void ID::DescribeReST(ODesc* d, bool roles_only) const
|
||||||
d->Add("`");
|
d->Add("`");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
type->DescribeReST(d, roles_only);
|
type->DescribeReST(d, roles_only);
|
||||||
|
|
||||||
|
if ( IsFunc(type->Tag()) )
|
||||||
|
{
|
||||||
|
auto ft = type->AsFuncType();
|
||||||
|
|
||||||
|
if ( ft->Flavor() == FUNC_FLAVOR_EVENT ||
|
||||||
|
ft->Flavor() == FUNC_FLAVOR_HOOK )
|
||||||
|
{
|
||||||
|
const auto& protos = ft->Prototypes();
|
||||||
|
|
||||||
|
if ( protos.size() > 1 )
|
||||||
|
{
|
||||||
|
auto first = true;
|
||||||
|
|
||||||
|
for ( const auto& proto : protos )
|
||||||
|
{
|
||||||
|
if ( first )
|
||||||
|
{
|
||||||
|
first = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->NL();
|
||||||
|
d->Add(":Type: :zeek:type:`");
|
||||||
|
d->Add(ft->FlavorString());
|
||||||
|
d->Add("` (");
|
||||||
|
proto.args->DescribeFieldsReST(d, true);
|
||||||
|
d->Add(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
d->NL();
|
d->NL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
49
src/Type.cc
49
src/Type.cc
|
@ -434,6 +434,7 @@ FuncType::FuncType(IntrusivePtr<RecordType> arg_args,
|
||||||
flavor = arg_flavor;
|
flavor = arg_flavor;
|
||||||
|
|
||||||
bool has_default_arg = false;
|
bool has_default_arg = false;
|
||||||
|
std::map<int, int> offsets;
|
||||||
|
|
||||||
for ( int i = 0; i < args->NumFields(); ++i )
|
for ( int i = 0; i < args->NumFields(); ++i )
|
||||||
{
|
{
|
||||||
|
@ -450,7 +451,10 @@ FuncType::FuncType(IntrusivePtr<RecordType> arg_args,
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_types->Append({NewRef{}, args->FieldType(i)});
|
arg_types->Append({NewRef{}, args->FieldType(i)});
|
||||||
|
offsets[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prototypes.emplace_back(Prototype{false, args, std::move(offsets)});
|
||||||
}
|
}
|
||||||
|
|
||||||
FuncType* FuncType::ShallowClone()
|
FuncType* FuncType::ShallowClone()
|
||||||
|
@ -460,6 +464,7 @@ FuncType* FuncType::ShallowClone()
|
||||||
f->arg_types = {NewRef{}, arg_types->AsTypeList()};
|
f->arg_types = {NewRef{}, arg_types->AsTypeList()};
|
||||||
f->yield = yield;
|
f->yield = yield;
|
||||||
f->flavor = flavor;
|
f->flavor = flavor;
|
||||||
|
f->prototypes = prototypes;
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,6 +579,50 @@ void FuncType::DescribeReST(ODesc* d, bool roles_only) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FuncType::AddPrototype(Prototype p)
|
||||||
|
{
|
||||||
|
prototypes.emplace_back(std::move(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<FuncType::Prototype> FuncType::FindPrototype(const RecordType& args) const
|
||||||
|
{
|
||||||
|
for ( auto i = 0u; i < prototypes.size(); ++i )
|
||||||
|
{
|
||||||
|
const auto& p = prototypes[i];
|
||||||
|
|
||||||
|
if ( args.NumFields() != p.args->NumFields() )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( args.NumFields() == 0 )
|
||||||
|
{
|
||||||
|
if ( p.args->NumFields() == 0 )
|
||||||
|
return p;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matched = true;
|
||||||
|
|
||||||
|
for ( auto i = 0; i < args.NumFields(); ++i )
|
||||||
|
{
|
||||||
|
auto ptype = p.args->FieldType(i);
|
||||||
|
auto desired_type = args.FieldType(i);
|
||||||
|
|
||||||
|
if ( ! same_type(ptype, desired_type) ||
|
||||||
|
! streq(args.FieldName(i), p.args->FieldName(i)) )
|
||||||
|
{
|
||||||
|
matched = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( matched )
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
TypeDecl::TypeDecl(IntrusivePtr<BroType> t, const char* i, attr_list* arg_attrs, bool in_record)
|
TypeDecl::TypeDecl(IntrusivePtr<BroType> t, const char* i, attr_list* arg_attrs, bool in_record)
|
||||||
: type(std::move(t)),
|
: type(std::move(t)),
|
||||||
attrs(arg_attrs ? make_intrusive<Attributes>(arg_attrs, type, in_record, false) : nullptr),
|
attrs(arg_attrs ? make_intrusive<Attributes>(arg_attrs, type, in_record, false) : nullptr),
|
||||||
|
|
29
src/Type.h
29
src/Type.h
|
@ -12,6 +12,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
// BRO types.
|
// BRO types.
|
||||||
|
|
||||||
|
@ -439,6 +440,17 @@ protected:
|
||||||
|
|
||||||
class FuncType final : public BroType {
|
class FuncType final : public BroType {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Prototype is only currently used for events and hooks which declare
|
||||||
|
* multiple signature prototypes that allow users to have handlers
|
||||||
|
* with various argument permutations.
|
||||||
|
*/
|
||||||
|
struct Prototype {
|
||||||
|
bool deprecated;
|
||||||
|
IntrusivePtr<RecordType> args;
|
||||||
|
std::map<int, int> offsets;
|
||||||
|
};
|
||||||
|
|
||||||
FuncType(IntrusivePtr<RecordType> args, IntrusivePtr<BroType> yield,
|
FuncType(IntrusivePtr<RecordType> args, IntrusivePtr<BroType> yield,
|
||||||
function_flavor f);
|
function_flavor f);
|
||||||
FuncType* ShallowClone() override;
|
FuncType* ShallowClone() override;
|
||||||
|
@ -464,12 +476,29 @@ public:
|
||||||
void Describe(ODesc* d) const override;
|
void Describe(ODesc* d) const override;
|
||||||
void DescribeReST(ODesc* d, bool roles_only = false) const override;
|
void DescribeReST(ODesc* d, bool roles_only = false) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new event/hook signature allowed for use in handlers.
|
||||||
|
*/
|
||||||
|
void AddPrototype(Prototype s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a prototype signature that matches the desired argument types.
|
||||||
|
*/
|
||||||
|
std::optional<Prototype> FindPrototype(const RecordType& args) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all allowed function prototypes.
|
||||||
|
*/
|
||||||
|
const std::vector<Prototype>& Prototypes() const
|
||||||
|
{ return prototypes; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FuncType() : BroType(TYPE_FUNC) { flavor = FUNC_FLAVOR_FUNCTION; }
|
FuncType() : BroType(TYPE_FUNC) { flavor = FUNC_FLAVOR_FUNCTION; }
|
||||||
IntrusivePtr<RecordType> args;
|
IntrusivePtr<RecordType> args;
|
||||||
IntrusivePtr<TypeList> arg_types;
|
IntrusivePtr<TypeList> arg_types;
|
||||||
IntrusivePtr<BroType> yield;
|
IntrusivePtr<BroType> yield;
|
||||||
function_flavor flavor;
|
function_flavor flavor;
|
||||||
|
std::vector<Prototype> prototypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TypeType final : public BroType {
|
class TypeType final : public BroType {
|
||||||
|
|
176
src/Var.cc
176
src/Var.cc
|
@ -29,13 +29,90 @@ static IntrusivePtr<Val> init_val(Expr* init, const BroType* t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool add_prototype(ID* id, BroType* t, attr_list* attrs,
|
||||||
|
const IntrusivePtr<Expr>& init)
|
||||||
|
{
|
||||||
|
if ( ! IsFunc(id->Type()->Tag()) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( ! IsFunc(t->Tag()) )
|
||||||
|
{
|
||||||
|
t->Error("type incompatible with previous definition", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto canon_ft = id->Type()->AsFuncType();
|
||||||
|
auto alt_ft = t->AsFuncType();
|
||||||
|
|
||||||
|
if ( canon_ft->Flavor() != alt_ft->Flavor() )
|
||||||
|
{
|
||||||
|
alt_ft->Error("incompatible function flavor", canon_ft);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( canon_ft->Flavor() == FUNC_FLAVOR_FUNCTION )
|
||||||
|
{
|
||||||
|
alt_ft->Error("redeclaration of function", canon_ft);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( init )
|
||||||
|
{
|
||||||
|
init->Error("initialization not allowed during event/hook alternate prototype declaration");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto canon_args = canon_ft->Args();
|
||||||
|
auto alt_args = alt_ft->Args();
|
||||||
|
|
||||||
|
if ( auto p = canon_ft->FindPrototype(*alt_args); p )
|
||||||
|
{
|
||||||
|
alt_ft->Error("alternate function prototype already exists", p->args.get());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<int, int> offsets;
|
||||||
|
|
||||||
|
for ( auto i = 0; i < alt_args->NumFields(); ++i )
|
||||||
|
{
|
||||||
|
auto field = alt_args->FieldName(i);
|
||||||
|
|
||||||
|
if ( alt_args->FieldDecl(i)->attrs )
|
||||||
|
{
|
||||||
|
alt_ft->Error(fmt("alternate function prototype arguments may not have attributes: arg '%s'", field), canon_ft);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto o = canon_args->FieldOffset(field);
|
||||||
|
|
||||||
|
if ( o < 0 )
|
||||||
|
{
|
||||||
|
alt_ft->Error(fmt("alternate function prototype arg '%s' not found in canonical prototype", field), canon_ft);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
offsets[i] = o;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto deprecated = false;
|
||||||
|
|
||||||
|
if ( attrs )
|
||||||
|
for ( const auto& a : *attrs )
|
||||||
|
if ( a->Tag() == ATTR_DEPRECATED )
|
||||||
|
deprecated = true;
|
||||||
|
|
||||||
|
FuncType::Prototype p{deprecated, {NewRef{}, alt_args}, std::move(offsets)};
|
||||||
|
canon_ft->AddPrototype(std::move(p));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void make_var(ID* id, IntrusivePtr<BroType> t, init_class c,
|
static void make_var(ID* id, IntrusivePtr<BroType> t, init_class c,
|
||||||
IntrusivePtr<Expr> init, attr_list* attr, decl_type dt,
|
IntrusivePtr<Expr> init, attr_list* attr, decl_type dt,
|
||||||
bool do_init)
|
bool do_init)
|
||||||
{
|
{
|
||||||
if ( id->Type() )
|
if ( id->Type() )
|
||||||
{
|
{
|
||||||
if ( id->IsRedefinable() || (! init && attr) )
|
if ( id->IsRedefinable() || (! init && attr && ! IsFunc(id->Type()->Tag())) )
|
||||||
{
|
{
|
||||||
BroObj* redef_obj = init ? (BroObj*) init.get() : (BroObj*) t.get();
|
BroObj* redef_obj = init ? (BroObj*) init.get() : (BroObj*) t.get();
|
||||||
if ( dt != VAR_REDEF )
|
if ( dt != VAR_REDEF )
|
||||||
|
@ -44,7 +121,11 @@ static void make_var(ID* id, IntrusivePtr<BroType> t, init_class c,
|
||||||
|
|
||||||
else if ( dt != VAR_REDEF || init || ! attr )
|
else if ( dt != VAR_REDEF || init || ! attr )
|
||||||
{
|
{
|
||||||
id->Error("already defined", init.get());
|
if ( IsFunc(id->Type()->Tag()) )
|
||||||
|
add_prototype(id, t.get(), attr, init);
|
||||||
|
else
|
||||||
|
id->Error("already defined", init.get());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -338,6 +419,41 @@ static bool has_attr(const attr_list* al, attr_tag tag)
|
||||||
return find_attr(al, tag) != nullptr;
|
return find_attr(al, tag) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::optional<FuncType::Prototype> func_type_check(const FuncType* decl, const FuncType* impl)
|
||||||
|
{
|
||||||
|
if ( decl->Flavor() != impl->Flavor() )
|
||||||
|
{
|
||||||
|
impl->Error("incompatible function flavor", decl);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( impl->Flavor() == FUNC_FLAVOR_FUNCTION )
|
||||||
|
{
|
||||||
|
if ( same_type(decl, impl) )
|
||||||
|
return decl->Prototypes()[0];
|
||||||
|
|
||||||
|
impl->Error("incompatible function types", decl);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return decl->FindPrototype(*impl->Args());
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool canonical_arg_types_match(const FuncType* decl, const FuncType* impl)
|
||||||
|
{
|
||||||
|
auto canon_args = decl->Args();
|
||||||
|
auto impl_args = impl->Args();
|
||||||
|
|
||||||
|
if ( canon_args->NumFields() != impl_args->NumFields() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for ( auto i = 0; i < canon_args->NumFields(); ++i )
|
||||||
|
if ( ! same_type(canon_args->FieldType(i), impl_args->FieldType(i)) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void begin_func(ID* id, const char* module_name, function_flavor flavor,
|
void begin_func(ID* id, const char* module_name, function_flavor flavor,
|
||||||
bool is_redef, IntrusivePtr<FuncType> t, attr_list* attrs)
|
bool is_redef, IntrusivePtr<FuncType> t, attr_list* attrs)
|
||||||
{
|
{
|
||||||
|
@ -351,16 +467,57 @@ void begin_func(ID* id, const char* module_name, function_flavor flavor,
|
||||||
t->ClearYieldType(flavor);
|
t->ClearYieldType(flavor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<FuncType::Prototype> prototype;
|
||||||
|
|
||||||
if ( id->Type() )
|
if ( id->Type() )
|
||||||
{
|
{
|
||||||
if ( ! same_type(id->Type(), t.get()) )
|
auto decl = id->Type()->AsFuncType();
|
||||||
id->Type()->Error("incompatible types", t.get());
|
prototype = func_type_check(decl, t.get());
|
||||||
|
|
||||||
|
if ( prototype )
|
||||||
|
{
|
||||||
|
if ( decl->Flavor() == FUNC_FLAVOR_FUNCTION )
|
||||||
|
{
|
||||||
|
// If a previous declaration of the function had &default
|
||||||
|
// params, automatically transfer any that are missing
|
||||||
|
// (convenience so that implementations don't need to specify
|
||||||
|
// the &default expression again).
|
||||||
|
transfer_arg_defaults(prototype->args.get(), t->Args());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Warn for trying to use &default parameters in hook/event
|
||||||
|
// handler body when it already has a declaration since only
|
||||||
|
// &default in the declaration has any effect.
|
||||||
|
auto args = t->Args();
|
||||||
|
|
||||||
|
for ( int i = 0; i < args->NumFields(); ++i )
|
||||||
|
{
|
||||||
|
auto f = args->FieldDecl(i);
|
||||||
|
|
||||||
|
if ( f->attrs && f->attrs->FindAttr(ATTR_DEFAULT) )
|
||||||
|
{
|
||||||
|
reporter->PushLocation(args->GetLocationInfo());
|
||||||
|
reporter->Warning(
|
||||||
|
"&default on parameter '%s' has no effect (not a %s declaration)",
|
||||||
|
args->FieldName(i), t->FlavorString().data());
|
||||||
|
reporter->PopLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( prototype->deprecated )
|
||||||
|
t->Warn("use of deprecated prototype", id);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
// If a previous declaration of the function had &default params,
|
{
|
||||||
// automatically transfer any that are missing (convenience so that
|
// Allow renaming arguments, but only for the canonical
|
||||||
// implementations don't need to specify the &default expression again).
|
// prototypes of hooks/events.
|
||||||
transfer_arg_defaults(id->Type()->AsFuncType()->Args(), t->Args());
|
if ( canonical_arg_types_match(decl, t.get()) )
|
||||||
|
prototype = decl->Prototypes()[0];
|
||||||
|
else
|
||||||
|
t->Error("use of undeclared alternate prototype", id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ( is_redef )
|
else if ( is_redef )
|
||||||
|
@ -410,6 +567,9 @@ void begin_func(ID* id, const char* module_name, function_flavor flavor,
|
||||||
|
|
||||||
arg_id = install_ID(arg_i->id, module_name, false, false);
|
arg_id = install_ID(arg_i->id, module_name, false, false);
|
||||||
arg_id->SetType(arg_i->type);
|
arg_id->SetType(arg_i->type);
|
||||||
|
|
||||||
|
if ( prototype )
|
||||||
|
arg_id->SetOffset(prototype->offsets[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( Attr* depr_attr = find_attr(attrs, ATTR_DEPRECATED) )
|
if ( Attr* depr_attr = find_attr(attrs, ATTR_DEPRECATED) )
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.alternate-event-hook-prototypes-invalid-arg/alternate-event-hook-prototypes-invalid-arg.zeek, line 5 and /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.alternate-event-hook-prototypes-invalid-arg/alternate-event-hook-prototypes-invalid-arg.zeek, line 4: alternate function prototype arg 'nope' not found in canonical prototype (event(nope:string; cantdothis:count;) and event(s:string; c:count;))
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.alternate-event-hook-prototypes-invalid-arg/alternate-event-hook-prototypes-invalid-arg.zeek, line 8 and /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.alternate-event-hook-prototypes-invalid-arg/alternate-event-hook-prototypes-invalid-arg.zeek, line 7: alternate function prototype arg 'andnotthiseither' not found in canonical prototype (hook(andnotthiseither:addr;) : bool and hook(s:string; c:count;) : bool)
|
|
@ -0,0 +1,12 @@
|
||||||
|
warning in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.alternate-event-hook-prototypes/alternate-event-hook-prototypes.zeek, line 68 and /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.alternate-event-hook-prototypes/alternate-event-hook-prototypes.zeek, line 10: use of deprecated prototype (hook(c:count;) : bool and my_hook)
|
||||||
|
my_hook, infinite, 13
|
||||||
|
my_hook, 13, infinite
|
||||||
|
my_hook, infinite
|
||||||
|
my_hook, 13
|
||||||
|
my_hook
|
||||||
|
my_event, enantiodromia, 42
|
||||||
|
my_event, 42, enantiodromia
|
||||||
|
my_event, enantiodromia
|
||||||
|
my_event, 42
|
||||||
|
my_event
|
||||||
|
foo, C
|
|
@ -0,0 +1,6 @@
|
||||||
|
foo, A, B, C
|
||||||
|
foo, A, B, C
|
||||||
|
reverse foo, A, B, C
|
||||||
|
foo a, A
|
||||||
|
foo b, B
|
||||||
|
foo c, C
|
|
@ -0,0 +1 @@
|
||||||
|
error in ./bad.zeek, line 2 and ./bad.zeek, line 1: alternate function prototype arguments may not have attributes: arg 'a' (event(c:string; b:string; a:string;) and event(a:string; b:string; c:string;))
|
|
@ -0,0 +1,6 @@
|
||||||
|
foo, A, B, C
|
||||||
|
foo, A, B, C
|
||||||
|
reverse foo, A, B, C
|
||||||
|
foo a, A
|
||||||
|
foo b, B
|
||||||
|
foo c, C
|
|
@ -0,0 +1,8 @@
|
||||||
|
warning in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.ineffective-default-args/ineffective-default-args.zeek, line 9: &default on parameter 'b' has no effect (not a event declaration)
|
||||||
|
warning in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.ineffective-default-args/ineffective-default-args.zeek, line 19: &default on parameter 'c' has no effect (not a event declaration)
|
||||||
|
bar, A, B
|
||||||
|
baz, A, B
|
||||||
|
qux, Q, Q
|
||||||
|
grault, A, B
|
||||||
|
corge, C
|
||||||
|
foo c, C
|
|
@ -0,0 +1,8 @@
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 13 and /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 4: use of undeclared alternate prototype (event(c:count; s:string;) and my_event)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 18 and /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 4: use of undeclared alternate prototype (event(s:string;) and my_event)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 23 and /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 4: use of undeclared alternate prototype (event(c:count;) and my_event)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 28 and /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 4: use of undeclared alternate prototype (event() and my_event)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 38 and /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 6: use of undeclared alternate prototype (hook(c:count; s:string;) : bool and my_hook)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 43 and /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 6: use of undeclared alternate prototype (hook(s:string;) : bool and my_hook)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 48 and /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 6: use of undeclared alternate prototype (hook(c:count;) : bool and my_hook)
|
||||||
|
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 53 and /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.undeclared-alternate-event-hook-prototype/undeclared-alternate-event-hook-prototype.zeek, line 6: use of undeclared alternate prototype (hook() : bool and my_hook)
|
|
@ -0,0 +1,24 @@
|
||||||
|
# @TEST-EXEC-FAIL: zeek -b %INPUT >out 2>&1
|
||||||
|
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out
|
||||||
|
|
||||||
|
global my_event: event(s: string, c: count);
|
||||||
|
global my_event: event(nope: string, cantdothis: count);
|
||||||
|
|
||||||
|
global my_hook: hook(s: string, c: count);
|
||||||
|
global my_hook: hook(andnotthiseither: addr);
|
||||||
|
|
||||||
|
event my_event(s: string, c: count)
|
||||||
|
{
|
||||||
|
print "my_event", s, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook my_hook(s: string, c: count)
|
||||||
|
{
|
||||||
|
print "my_hook", s, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event zeek_init()
|
||||||
|
{
|
||||||
|
hook my_hook("infinite", 13);
|
||||||
|
event my_event("enantiodromia", 42);
|
||||||
|
}
|
83
testing/btest/language/alternate-event-hook-prototypes.zeek
Normal file
83
testing/btest/language/alternate-event-hook-prototypes.zeek
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
# @TEST-EXEC: zeek -b %INPUT >out 2>&1
|
||||||
|
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out
|
||||||
|
|
||||||
|
global my_event: event(s: string, c: count);
|
||||||
|
global my_event: event(c: count, s: string);
|
||||||
|
global my_event: event(s: string);
|
||||||
|
global my_event: event(c: count);
|
||||||
|
global my_event: event();
|
||||||
|
|
||||||
|
global my_hook: hook(s: string, c: count);
|
||||||
|
global my_hook: hook(c: count, s: string);
|
||||||
|
global my_hook: hook(s: string);
|
||||||
|
global my_hook: hook(c: count) &deprecated;
|
||||||
|
global my_hook: hook();
|
||||||
|
|
||||||
|
# Required Frame size gets (re)calculated on AddBody, so this "foo" setup is
|
||||||
|
# checking that if the only existing body doesn't use all arguments, the Frame
|
||||||
|
# size is still allocated sufficiently to hold all arguments of the canonical
|
||||||
|
# prototype.
|
||||||
|
global foo: event(a: string, b: string, c: string);
|
||||||
|
global foo: event(c: string);
|
||||||
|
|
||||||
|
event foo(c: string)
|
||||||
|
{
|
||||||
|
print "foo", c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event my_event(s: string, c: count)
|
||||||
|
{
|
||||||
|
print "my_event", s, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event my_event(c: count, s: string)
|
||||||
|
{
|
||||||
|
print "my_event", c, s;
|
||||||
|
}
|
||||||
|
|
||||||
|
event my_event(s: string)
|
||||||
|
{
|
||||||
|
print "my_event", s;
|
||||||
|
}
|
||||||
|
|
||||||
|
event my_event(c: count)
|
||||||
|
{
|
||||||
|
print "my_event", c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event my_event()
|
||||||
|
{
|
||||||
|
print "my_event";
|
||||||
|
}
|
||||||
|
|
||||||
|
hook my_hook(s: string, c: count)
|
||||||
|
{
|
||||||
|
print "my_hook", s, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook my_hook(c: count, s: string)
|
||||||
|
{
|
||||||
|
print "my_hook", c, s;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook my_hook(s: string)
|
||||||
|
{
|
||||||
|
print "my_hook", s;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook my_hook(c: count)
|
||||||
|
{
|
||||||
|
print "my_hook", c;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook my_hook()
|
||||||
|
{
|
||||||
|
print "my_hook";
|
||||||
|
}
|
||||||
|
|
||||||
|
event zeek_init()
|
||||||
|
{
|
||||||
|
hook my_hook("infinite", 13);
|
||||||
|
event my_event("enantiodromia", 42);
|
||||||
|
event foo("A", "B", "C");
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
# @TEST-EXEC: zeek -b %INPUT > out
|
||||||
|
# @TEST-EXEC: btest-diff out
|
||||||
|
|
||||||
|
global foo: event(a: string, b: string, c: string);
|
||||||
|
global foo: event(c: string, b: string, a: string);
|
||||||
|
global foo: event(a: string);
|
||||||
|
global foo: event(b: string);
|
||||||
|
global foo: event(c: string);
|
||||||
|
|
||||||
|
event foo(a: string, b: string, c: string)
|
||||||
|
{
|
||||||
|
print "foo", a, b, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event foo(mya: string, b: string, c: string)
|
||||||
|
{
|
||||||
|
print "foo", mya, b, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event foo(c: string, b: string, a: string)
|
||||||
|
{
|
||||||
|
print "reverse foo", a, b, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event foo(a: string)
|
||||||
|
{
|
||||||
|
print "foo a", a;
|
||||||
|
}
|
||||||
|
|
||||||
|
event foo(b: string)
|
||||||
|
{
|
||||||
|
print "foo b", b;
|
||||||
|
}
|
||||||
|
|
||||||
|
event foo(c: string)
|
||||||
|
{
|
||||||
|
print "foo c", c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event zeek_init()
|
||||||
|
{
|
||||||
|
event foo("A", "B", "C");
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
# @TEST-EXEC: zeek -b %INPUT >out
|
||||||
|
# @TEST-EXEC-FAIL: zeek -b bad.zeek >errors 2>&1
|
||||||
|
# @TEST-EXEC: btest-diff out
|
||||||
|
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff errors
|
||||||
|
|
||||||
|
global foo: event(a: string, b: string, c: string &default="C");
|
||||||
|
global foo: event(c: string, b: string, a: string);
|
||||||
|
global foo: event(a: string);
|
||||||
|
global foo: event(b: string);
|
||||||
|
global foo: event(c: string);
|
||||||
|
|
||||||
|
event foo(a: string, b: string, c: string)
|
||||||
|
{
|
||||||
|
print "foo", a, b, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event foo(mya: string, b: string, c: string)
|
||||||
|
{
|
||||||
|
print "foo", mya, b, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event foo(c: string, b: string, a: string)
|
||||||
|
{
|
||||||
|
print "reverse foo", a, b, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event foo(a: string)
|
||||||
|
{
|
||||||
|
print "foo a", a;
|
||||||
|
}
|
||||||
|
|
||||||
|
event foo(b: string)
|
||||||
|
{
|
||||||
|
print "foo b", b;
|
||||||
|
}
|
||||||
|
|
||||||
|
event foo(c: string)
|
||||||
|
{
|
||||||
|
print "foo c", c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event zeek_init()
|
||||||
|
{
|
||||||
|
event foo("A", "B");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TEST-START-FILE bad.zeek
|
||||||
|
global foo: event(a: string, b: string, c: string &default="C");
|
||||||
|
global foo: event(c: string, b: string, a: string &default="A");
|
||||||
|
@TEST-END-FILE bad.zeek
|
54
testing/btest/language/ineffective-default-args.zeek
Normal file
54
testing/btest/language/ineffective-default-args.zeek
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# @TEST-EXEC: zeek -b %INPUT >out 2>&1
|
||||||
|
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out
|
||||||
|
|
||||||
|
global grault: event(a: string, b: string &default="B");
|
||||||
|
|
||||||
|
global foo: event(a: string, b: string, c: string &default="C");
|
||||||
|
global foo: event(c: string);
|
||||||
|
|
||||||
|
event grault(a: string, b: string &default="G")
|
||||||
|
{
|
||||||
|
print "grault", a, b;
|
||||||
|
}
|
||||||
|
|
||||||
|
event corge(c: string &default="C")
|
||||||
|
{
|
||||||
|
print "corge", c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event foo(c: string &default="CCCC")
|
||||||
|
{
|
||||||
|
print "foo c", c;
|
||||||
|
}
|
||||||
|
|
||||||
|
global bar: function(a: string, b: string);
|
||||||
|
|
||||||
|
function bar(a: string &default="A", b: string &default="B")
|
||||||
|
{
|
||||||
|
print "bar", a, b;
|
||||||
|
}
|
||||||
|
|
||||||
|
global baz: function(a: string &default="A", b: string &default="B");
|
||||||
|
|
||||||
|
function baz(a: string, b: string)
|
||||||
|
{
|
||||||
|
print "baz", a, b;
|
||||||
|
}
|
||||||
|
|
||||||
|
global qux: function(a: string &default="A", b: string &default="B");
|
||||||
|
|
||||||
|
function qux(a: string &default="Q", b: string &default="Q")
|
||||||
|
{
|
||||||
|
print "qux", a, b;
|
||||||
|
}
|
||||||
|
|
||||||
|
event zeek_init()
|
||||||
|
{
|
||||||
|
bar();
|
||||||
|
baz();
|
||||||
|
qux();
|
||||||
|
event grault("A");
|
||||||
|
event corge();
|
||||||
|
event foo("A", "B");
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
# @TEST-EXEC-FAIL: zeek -b %INPUT >out 2>&1
|
||||||
|
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out
|
||||||
|
|
||||||
|
global my_event: event(s: string, c: count);
|
||||||
|
|
||||||
|
global my_hook: hook(s: string, c: count);
|
||||||
|
|
||||||
|
event my_event(s: string, c: count)
|
||||||
|
{
|
||||||
|
print "my_event", s, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event my_event(c: count, s: string)
|
||||||
|
{
|
||||||
|
print "my_event", c, s;
|
||||||
|
}
|
||||||
|
|
||||||
|
event my_event(s: string)
|
||||||
|
{
|
||||||
|
print "my_event", s;
|
||||||
|
}
|
||||||
|
|
||||||
|
event my_event(c: count)
|
||||||
|
{
|
||||||
|
print "my_event", c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event my_event()
|
||||||
|
{
|
||||||
|
print "my_event";
|
||||||
|
}
|
||||||
|
|
||||||
|
hook my_hook(s: string, c: count)
|
||||||
|
{
|
||||||
|
print "my_hook", s, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook my_hook(c: count, s: string)
|
||||||
|
{
|
||||||
|
print "my_hook", c, s;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook my_hook(s: string)
|
||||||
|
{
|
||||||
|
print "my_hook", s;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook my_hook(c: count)
|
||||||
|
{
|
||||||
|
print "my_hook", c;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook my_hook()
|
||||||
|
{
|
||||||
|
print "my_hook";
|
||||||
|
}
|
||||||
|
|
||||||
|
event zeek_init()
|
||||||
|
{
|
||||||
|
hook my_hook("infinite", 13);
|
||||||
|
event my_event("enantiodromia", 42);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue