diff --git a/CHANGES b/CHANGES index 9aa74a5eb9..82c4ebdf5e 100644 --- a/CHANGES +++ b/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//". 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 * Remove 'using namespace std' as well as other using statements from headers. diff --git a/VERSION b/VERSION index ca15c8f14a..caa9db90cd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.2.0-dev.382 +3.2.0-dev.391 diff --git a/aux/bifcl b/aux/bifcl index 69d7443794..abfe5cb864 160000 --- a/aux/bifcl +++ b/aux/bifcl @@ -1 +1 @@ -Subproject commit 69d7443794e8712344561a49517340aab3e58ff4 +Subproject commit abfe5cb864a17b8c06c70d4674b32a51280ee62b diff --git a/doc b/doc index 23327f8795..fe6fe81c15 160000 --- a/doc +++ b/doc @@ -1 +1 @@ -Subproject commit 23327f87955b382729db1419ba8e75feba038c05 +Subproject commit fe6fe81c1524bb2d41b1d1d2fa80177e1437e501 diff --git a/scripts/base/frameworks/netcontrol/non-cluster.zeek b/scripts/base/frameworks/netcontrol/non-cluster.zeek index e1363fd883..3099d0c840 100644 --- a/scripts/base/frameworks/netcontrol/non-cluster.zeek +++ b/scripts/base/frameworks/netcontrol/non-cluster.zeek @@ -28,7 +28,7 @@ event rule_expire(r: Rule, p: PluginState) &priority=-5 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); @@ -36,7 +36,7 @@ event rule_exists(r: Rule, p: PluginState, msg: string &default="") &priority=5 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); @@ -44,7 +44,7 @@ event rule_added(r: Rule, p: PluginState, msg: string &default="") &priority=5 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); } @@ -54,7 +54,7 @@ event rule_timeout(r: Rule, i: FlowInfo, p: PluginState) &priority=-5 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); } diff --git a/scripts/policy/frameworks/netcontrol/catch-and-release.zeek b/scripts/policy/frameworks/netcontrol/catch-and-release.zeek index b11170929f..c0182bd5bf 100644 --- a/scripts/policy/frameworks/netcontrol/catch-and-release.zeek +++ b/scripts/policy/frameworks/netcontrol/catch-and-release.zeek @@ -259,7 +259,7 @@ function cr_check_rule(r: Rule): bool @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) ) return; diff --git a/src/Func.cc b/src/Func.cc index efefa3e04a..059d3807fd 100644 --- a/src/Func.cc +++ b/src/Func.cc @@ -449,6 +449,11 @@ void BroFunc::AddBody(IntrusivePtr new_body, id_list* new_inits, if ( new_frame_size > frame_size ) frame_size = new_frame_size; + auto num_args = FType()->Args()->NumFields(); + + if ( num_args > static_cast(frame_size) ) + frame_size = num_args; + new_body = AddInits(std::move(new_body), new_inits); if ( Flavor() == FUNC_FLAVOR_FUNCTION ) diff --git a/src/ID.cc b/src/ID.cc index 2475ef9a1e..34289ef574 100644 --- a/src/ID.cc +++ b/src/ID.cc @@ -431,8 +431,42 @@ void ID::DescribeReST(ODesc* d, bool roles_only) const d->Add("`"); } else + { 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(); } diff --git a/src/Type.cc b/src/Type.cc index 39d4f4425b..2683356722 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -434,6 +434,7 @@ FuncType::FuncType(IntrusivePtr arg_args, flavor = arg_flavor; bool has_default_arg = false; + std::map offsets; for ( int i = 0; i < args->NumFields(); ++i ) { @@ -450,7 +451,10 @@ FuncType::FuncType(IntrusivePtr arg_args, } arg_types->Append({NewRef{}, args->FieldType(i)}); + offsets[i] = i; } + + prototypes.emplace_back(Prototype{false, args, std::move(offsets)}); } FuncType* FuncType::ShallowClone() @@ -460,6 +464,7 @@ FuncType* FuncType::ShallowClone() f->arg_types = {NewRef{}, arg_types->AsTypeList()}; f->yield = yield; f->flavor = flavor; + f->prototypes = prototypes; 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::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 t, const char* i, attr_list* arg_attrs, bool in_record) : type(std::move(t)), attrs(arg_attrs ? make_intrusive(arg_attrs, type, in_record, false) : nullptr), diff --git a/src/Type.h b/src/Type.h index 9b4e8d111d..a47239ac2d 100644 --- a/src/Type.h +++ b/src/Type.h @@ -12,6 +12,7 @@ #include #include #include +#include // BRO types. @@ -439,6 +440,17 @@ protected: class FuncType final : public BroType { 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 args; + std::map offsets; + }; + FuncType(IntrusivePtr args, IntrusivePtr yield, function_flavor f); FuncType* ShallowClone() override; @@ -464,12 +476,29 @@ public: void Describe(ODesc* d) 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 FindPrototype(const RecordType& args) const; + + /** + * Returns all allowed function prototypes. + */ + const std::vector& Prototypes() const + { return prototypes; } + protected: FuncType() : BroType(TYPE_FUNC) { flavor = FUNC_FLAVOR_FUNCTION; } IntrusivePtr args; IntrusivePtr arg_types; IntrusivePtr yield; function_flavor flavor; + std::vector prototypes; }; class TypeType final : public BroType { diff --git a/src/Var.cc b/src/Var.cc index a6e2a79f42..b170c20ddc 100644 --- a/src/Var.cc +++ b/src/Var.cc @@ -29,13 +29,90 @@ static IntrusivePtr init_val(Expr* init, const BroType* t, } } +static bool add_prototype(ID* id, BroType* t, attr_list* attrs, + const IntrusivePtr& 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 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 t, init_class c, IntrusivePtr init, attr_list* attr, decl_type dt, bool do_init) { 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(); if ( dt != VAR_REDEF ) @@ -44,7 +121,11 @@ static void make_var(ID* id, IntrusivePtr t, init_class c, 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; } } @@ -338,6 +419,41 @@ static bool has_attr(const attr_list* al, attr_tag tag) return find_attr(al, tag) != nullptr; } +static std::optional 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, bool is_redef, IntrusivePtr t, attr_list* attrs) { @@ -351,16 +467,57 @@ void begin_func(ID* id, const char* module_name, function_flavor flavor, t->ClearYieldType(flavor); } + std::optional prototype; + if ( id->Type() ) { - if ( ! same_type(id->Type(), t.get()) ) - id->Type()->Error("incompatible types", t.get()); + auto decl = id->Type()->AsFuncType(); + 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 - // 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(id->Type()->AsFuncType()->Args(), t->Args()); + { + // Allow renaming arguments, but only for the canonical + // prototypes of hooks/events. + 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 ) @@ -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->SetType(arg_i->type); + + if ( prototype ) + arg_id->SetOffset(prototype->offsets[i]); } if ( Attr* depr_attr = find_attr(attrs, ATTR_DEPRECATED) ) diff --git a/testing/btest/Baseline/language.alternate-event-hook-prototypes-invalid-arg/out b/testing/btest/Baseline/language.alternate-event-hook-prototypes-invalid-arg/out new file mode 100644 index 0000000000..b1675cdbf1 --- /dev/null +++ b/testing/btest/Baseline/language.alternate-event-hook-prototypes-invalid-arg/out @@ -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) diff --git a/testing/btest/Baseline/language.alternate-event-hook-prototypes/out b/testing/btest/Baseline/language.alternate-event-hook-prototypes/out new file mode 100644 index 0000000000..aa70ccc747 --- /dev/null +++ b/testing/btest/Baseline/language.alternate-event-hook-prototypes/out @@ -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 diff --git a/testing/btest/Baseline/language.alternate-prototypes-arg-matching/out b/testing/btest/Baseline/language.alternate-prototypes-arg-matching/out new file mode 100644 index 0000000000..19682ecd68 --- /dev/null +++ b/testing/btest/Baseline/language.alternate-prototypes-arg-matching/out @@ -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 diff --git a/testing/btest/Baseline/language.alternate-prototypes-default-args/errors b/testing/btest/Baseline/language.alternate-prototypes-default-args/errors new file mode 100644 index 0000000000..ec8fac7ea0 --- /dev/null +++ b/testing/btest/Baseline/language.alternate-prototypes-default-args/errors @@ -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;)) diff --git a/testing/btest/Baseline/language.alternate-prototypes-default-args/out b/testing/btest/Baseline/language.alternate-prototypes-default-args/out new file mode 100644 index 0000000000..19682ecd68 --- /dev/null +++ b/testing/btest/Baseline/language.alternate-prototypes-default-args/out @@ -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 diff --git a/testing/btest/Baseline/language.ineffective-default-args/out b/testing/btest/Baseline/language.ineffective-default-args/out new file mode 100644 index 0000000000..1d7e508a4f --- /dev/null +++ b/testing/btest/Baseline/language.ineffective-default-args/out @@ -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 diff --git a/testing/btest/Baseline/language.undeclared-alternate-event-hook-prototype/out b/testing/btest/Baseline/language.undeclared-alternate-event-hook-prototype/out new file mode 100644 index 0000000000..0e2d386615 --- /dev/null +++ b/testing/btest/Baseline/language.undeclared-alternate-event-hook-prototype/out @@ -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) diff --git a/testing/btest/language/alternate-event-hook-prototypes-invalid-arg.zeek b/testing/btest/language/alternate-event-hook-prototypes-invalid-arg.zeek new file mode 100644 index 0000000000..61bcc79b66 --- /dev/null +++ b/testing/btest/language/alternate-event-hook-prototypes-invalid-arg.zeek @@ -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); + } diff --git a/testing/btest/language/alternate-event-hook-prototypes.zeek b/testing/btest/language/alternate-event-hook-prototypes.zeek new file mode 100644 index 0000000000..62573479d6 --- /dev/null +++ b/testing/btest/language/alternate-event-hook-prototypes.zeek @@ -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"); + } diff --git a/testing/btest/language/alternate-prototypes-arg-matching.zeek b/testing/btest/language/alternate-prototypes-arg-matching.zeek new file mode 100644 index 0000000000..9d97d978c3 --- /dev/null +++ b/testing/btest/language/alternate-prototypes-arg-matching.zeek @@ -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"); + } + diff --git a/testing/btest/language/alternate-prototypes-default-args.zeek b/testing/btest/language/alternate-prototypes-default-args.zeek new file mode 100644 index 0000000000..a7eeafac20 --- /dev/null +++ b/testing/btest/language/alternate-prototypes-default-args.zeek @@ -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 diff --git a/testing/btest/language/ineffective-default-args.zeek b/testing/btest/language/ineffective-default-args.zeek new file mode 100644 index 0000000000..2fff7dcda2 --- /dev/null +++ b/testing/btest/language/ineffective-default-args.zeek @@ -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"); + } + diff --git a/testing/btest/language/undeclared-alternate-event-hook-prototype.zeek b/testing/btest/language/undeclared-alternate-event-hook-prototype.zeek new file mode 100644 index 0000000000..1522a91bc7 --- /dev/null +++ b/testing/btest/language/undeclared-alternate-event-hook-prototype.zeek @@ -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); + }