From 9b6934eab8efb7b311f8c83c86188b4721a6faf3 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 9 Apr 2020 20:20:38 -0700 Subject: [PATCH] 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. --- src/Type.cc | 15 ++++--- src/Var.cc | 26 ++++++++++- .../out | 2 +- .../out | 6 +++ .../alternate-prototypes-arg-matching.zeek | 44 +++++++++++++++++++ 5 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 testing/btest/Baseline/language.alternate-prototypes-arg-matching/out create mode 100644 testing/btest/language/alternate-prototypes-arg-matching.zeek diff --git a/src/Type.cc b/src/Type.cc index ef4e4b4fad..c42adf19bc 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -584,8 +584,10 @@ void FuncType::AddPrototype(Prototype p) std::optional FuncType::FindPrototype(const RecordType& args) const { - for ( const auto& p : prototypes ) + for ( auto i = 0u; i < prototypes.size(); ++i ) { + const auto& p = prototypes[i]; + if ( args.NumFields() != p.args->NumFields() ) continue; @@ -604,11 +606,12 @@ std::optional FuncType::FindPrototype(const RecordType& arg auto ptype = p.args->FieldType(i); auto desired_type = args.FieldType(i); - if ( same_type(ptype, desired_type) ) - continue; - - matched = false; - break; + if ( ! same_type(ptype, desired_type) || + ! streq(args.FieldName(i), p.args->FieldName(i)) ) + { + matched = false; + break; + } } if ( matched ) diff --git a/src/Var.cc b/src/Var.cc index 061fb9c099..8b283e4a81 100644 --- a/src/Var.cc +++ b/src/Var.cc @@ -432,6 +432,21 @@ static std::optional func_type_check(const FuncType* decl, 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) { @@ -462,7 +477,16 @@ void begin_func(ID* id, const char* module_name, function_flavor flavor, t->Warn("use of deprecated prototype", id); } else - t->Error("use of undeclared alternate prototype", id); + { + auto decl = id->Type()->AsFuncType(); + + // 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 ) 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 index eee2a611e1..b1675cdbf1 100644 --- a/testing/btest/Baseline/language.alternate-event-hook-prototypes-invalid-arg/out +++ b/testing/btest/Baseline/language.alternate-event-hook-prototypes-invalid-arg/out @@ -1,2 +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 already exists (event(nope:string; cantdothis:count;) and record { 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 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-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/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"); + } +