diff --git a/CHANGES b/CHANGES index bfe927190c..9e00104912 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +5.1.0-dev.128 | 2022-06-27 13:04:47 -0700 + + * removed deprecated capture-by-reference closures (Vern Paxson, Corelight) + 5.1.0-dev.126 | 2022-06-27 11:43:27 -0700 * GH-2183: Rework Packet checksummed variable naming (Tim Wojtulewicz, Corelight) diff --git a/VERSION b/VERSION index bedc10a87b..b8ab635c21 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.1.0-dev.126 +5.1.0-dev.128 diff --git a/src/Expr.cc b/src/Expr.cc index 78e0449780..d495472a20 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -4702,7 +4702,11 @@ LambdaExpr::LambdaExpr(std::unique_ptr arg_ing, IDPList ar SetType(ingredients->id->GetType()); - CheckCaptures(when_parent); + if ( ! CheckCaptures(when_parent) ) + { + SetError(); + return; + } // Install a dummy version of the function globally for use only // when broker provides a closure. @@ -4747,32 +4751,28 @@ LambdaExpr::LambdaExpr(std::unique_ptr arg_ing, IDPList ar lambda_id->SetConst(); } -void LambdaExpr::CheckCaptures(StmtPtr when_parent) +bool LambdaExpr::CheckCaptures(StmtPtr when_parent) { auto ft = type->AsFuncType(); const auto& captures = ft->GetCaptures(); - capture_by_ref = false; + auto desc = when_parent ? "\"when\" statement" : "lambda"; if ( ! captures ) { if ( outer_ids.size() > 0 ) { - // TODO: Remove in v5.1: these deprecated closure semantics - reporter->Warning( - "use of outer identifiers in lambdas without [] captures is deprecated: %s%s", - outer_ids.size() > 1 ? "e.g., " : "", outer_ids[0]->Name()); - capture_by_ref = true; + reporter->Error("%s uses outer identifiers without [] captures: %s%s", desc, + outer_ids.size() > 1 ? "e.g., " : "", outer_ids[0]->Name()); + return false; } - return; + return true; } std::set outer_is_matched; std::set capture_is_matched; - auto desc = when_parent ? "\"when\" statement" : "lambda"; - for ( const auto& c : *captures ) { auto cid = c.id.get(); @@ -4790,7 +4790,8 @@ void LambdaExpr::CheckCaptures(StmtPtr when_parent) when_parent->Error(msg); else ExprError(msg); - continue; + + return false; } for ( auto id : outer_ids ) @@ -4810,6 +4811,8 @@ void LambdaExpr::CheckCaptures(StmtPtr when_parent) when_parent->Error(msg); else ExprError(msg); + + return false; } for ( const auto& c : *captures ) @@ -4822,8 +4825,12 @@ void LambdaExpr::CheckCaptures(StmtPtr when_parent) when_parent->Error(msg); else ExprError(msg); + + return false; } } + + return true; } ScopePtr LambdaExpr::GetScope() const @@ -4836,10 +4843,7 @@ ValPtr LambdaExpr::Eval(Frame* f) const auto lamb = make_intrusive(ingredients->id, ingredients->body, ingredients->inits, ingredients->frame_size, ingredients->priority); - if ( capture_by_ref ) - lamb->AddClosure(outer_ids, f); - else - lamb->CreateCaptures(f); + lamb->CreateCaptures(f); // Set name to corresponding dummy func. // Allows for lookups by the receiver. @@ -4856,6 +4860,10 @@ void LambdaExpr::ExprDescribe(ODesc* d) const TraversalCode LambdaExpr::Traverse(TraversalCallback* cb) const { + if ( IsError() ) + // Not well-formed. + return TC_CONTINUE; + TraversalCode tc = cb->PreExpr(this); HANDLE_TC_EXPR_PRE(tc); diff --git a/src/Expr.h b/src/Expr.h index 6341a659ad..d748896eaa 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -1480,13 +1480,11 @@ protected: void ExprDescribe(ODesc* d) const override; private: - void CheckCaptures(StmtPtr when_parent); + bool CheckCaptures(StmtPtr when_parent); std::unique_ptr ingredients; IDPtr lambda_id; - IDPList outer_ids; - bool capture_by_ref; // if true, use deprecated reference semantics std::string my_name; }; diff --git a/src/Frame.cc b/src/Frame.cc index a3539157e9..dc1709c54b 100644 --- a/src/Frame.cc +++ b/src/Frame.cc @@ -30,8 +30,6 @@ Frame::Frame(int arg_size, const ScriptFunc* func, const zeek::Args* fn_args) call = nullptr; delayed = false; - closure = nullptr; - // We could Ref()/Unref() the captures frame, but there's really // no need because by definition this current frame exists to // enable execution of the function, and its captures frame won't @@ -42,61 +40,14 @@ Frame::Frame(int arg_size, const ScriptFunc* func, const zeek::Args* fn_args) current_offset = 0; } -Frame::~Frame() - { - if ( functions_with_closure_frame_reference ) - { - for ( auto& func : *functions_with_closure_frame_reference ) - { - func->StrengthenClosureReference(this); - Unref(func); - } - } - - if ( ! weak_closure_ref ) - Unref(closure); - - for ( auto& i : outer_ids ) - Unref(i); - - for ( int i = 0; i < size; ++i ) - ClearElement(i); - } - -void Frame::AddFunctionWithClosureRef(ScriptFunc* func) - { - Ref(func); - - if ( ! functions_with_closure_frame_reference ) - functions_with_closure_frame_reference = std::make_unique>(); - - functions_with_closure_frame_reference->emplace_back(func); - } - void Frame::SetElement(int n, ValPtr v) { n += current_offset; - - ClearElement(n); - frame[n] = {std::move(v), false}; - } - -void Frame::SetElementWeak(int n, Val* v) - { - n += current_offset; - - ClearElement(n); - frame[n] = {{AdoptRef{}, v}, true}; + frame[n] = std::move(v); } void Frame::SetElement(const ID* id, ValPtr v) { - if ( closure && IsOuterID(id) ) - { - closure->SetElement(id, std::move(v)); - return; - } - if ( captures ) { auto cap_off = captures_offset_map->find(id->Name()); @@ -107,29 +58,11 @@ void Frame::SetElement(const ID* id, ValPtr v) } } - // do we have an offset for it? - if ( offset_map && ! offset_map->empty() ) - { - auto where = offset_map->find(std::string(id->Name())); - - if ( where != offset_map->end() ) - { - // Need to add a Ref to 'v' since the SetElement() for - // id->Offset() below is otherwise responsible for keeping track - // of the implied reference count of the passed-in 'v' argument. - // i.e. if we end up storing it twice, we need an addition Ref. - SetElement(where->second, v); - } - } - SetElement(id->Offset(), std::move(v)); } const ValPtr& Frame::GetElementByID(const ID* id) const { - if ( closure && IsOuterID(id) ) - return closure->GetElementByID(id); - if ( captures ) { auto cap_off = captures_offset_map->find(id->Name()); @@ -137,35 +70,13 @@ const ValPtr& Frame::GetElementByID(const ID* id) const return captures->GetElement(cap_off->second); } - // do we have an offset for it? - if ( offset_map && ! offset_map->empty() ) - { - auto where = offset_map->find(std::string(id->Name())); - if ( where != offset_map->end() ) - return frame[where->second + current_offset].val; - } - - return frame[id->Offset() + current_offset].val; + return frame[id->Offset() + current_offset]; } void Frame::Reset(int startIdx) { - if ( functions_with_closure_frame_reference ) - { - for ( auto& func : *functions_with_closure_frame_reference ) - { - // A lambda could be escaping its enclosing Frame at this point so - // it needs to claim some ownership (or copy) of the Frame in - // order to be of any further use. - func->StrengthenClosureReference(this); - Unref(func); - } - - functions_with_closure_frame_reference.reset(); - } - for ( int i = startIdx + current_offset; i < size; ++i ) - ClearElement(i); + frame[i] = nullptr; } void Frame::Describe(ODesc* d) const @@ -179,14 +90,14 @@ void Frame::Describe(ODesc* d) const for ( int i = 0; i < size; ++i ) { - d->Add(frame[i].val != nullptr); + d->Add(frame[i] != nullptr); d->SP(); } } for ( int i = 0; i < size; ++i ) - if ( frame[i].val ) - frame[i].val->Describe(d); + if ( frame[i] ) + frame[i]->Describe(d); else if ( d->IsReadable() ) d->Add(""); } @@ -195,18 +106,13 @@ Frame* Frame::Clone() const { Frame* other = new Frame(size, function, func_args); - if ( offset_map ) - other->offset_map = std::make_unique(*offset_map); - - other->CaptureClosure(closure, outer_ids); - other->call = call; other->assoc = assoc; other->trigger = trigger; for ( int i = 0; i < size; i++ ) - if ( frame[i].val ) - other->frame[i].val = frame[i].val->Clone(); + if ( frame[i] ) + other->frame[i] = frame[i]->Clone(); // Note, there's no need to clone "captures" or "captures_offset_map" // since those get created fresh when constructing "other". @@ -222,176 +128,6 @@ static bool val_is_func(const ValPtr& v, ScriptFunc* func) return v->AsFunc() == func; } -void Frame::CloneNonFuncElement(int offset, ScriptFunc* func, Frame* other) const - { - const auto& v = frame[offset].val; - - if ( ! v ) - return; - - if ( val_is_func(v, func) ) - { - other->SetElementWeak(offset, v.get()); - return; - } - - auto rval = v->Clone(); - other->SetElement(offset, std::move(rval)); - } - -Frame* Frame::SelectiveClone(const IDPList& selection, ScriptFunc* func) const - { - if ( selection.length() == 0 ) - return nullptr; - - IDPList us; - // and - IDPList them; - - for ( const auto& we : selection ) - { - if ( ! IsOuterID(we) ) - us.append(we); - else - them.append(we); - } - - Frame* other = new Frame(size, function, func_args); - - for ( const auto& id : us ) - { - if ( offset_map && ! offset_map->empty() ) - { - auto where = offset_map->find(std::string(id->Name())); - if ( where != offset_map->end() ) - { - CloneNonFuncElement(where->second, func, other); - continue; - } - } - - if ( ! frame[id->Offset() + current_offset].val ) - reporter->InternalError("Attempted to clone an id ('%s') with no associated value.", - id->Name()); - - CloneNonFuncElement(id->Offset(), func, other); - } - - /** - * What to do here depends on what the expected behavior of a copy - * operation on a function with a closure is. As we let functions - * mutate their closures, it seems reasonable that when cloned, the - * clone should continue to mutate the same closure as the function - * doesn't **own** the closure. Uncommenting the below if statement - * will change that behavior such that the function also copies the - * closure frame. - */ - // if ( closure ) - // other->closure = closure->SelectiveClone(them); - // other->outer_ids = outer_ids; - - if ( closure ) - other->CaptureClosure(closure, outer_ids); - - if ( offset_map ) - { - if ( ! other->offset_map ) - other->offset_map = std::make_unique(*offset_map); - else - *(other->offset_map) = *offset_map; - } - else - other->offset_map.reset(); - - return other; - } - -broker::expected Frame::SerializeClosureFrame(const IDPList& selection) - { - broker::vector rval; - - if ( selection.length() == 0 ) - // Easy - no captures, so frame is irrelvant. - return {std::move(rval)}; - - IDPList us; - // and - IDPList them; - - OffsetMap new_map; - if ( offset_map ) - new_map = *offset_map; - - for ( const auto& we : selection ) - { - if ( IsOuterID(we) ) - them.append(we); - else - { - us.append(we); - new_map.insert(std::make_pair(std::string(we->Name()), we->Offset())); - } - } - - if ( them.length() ) - { - if ( ! closure ) - reporter->InternalError( - "Attempting to serialize values from a frame that does not exist."); - - rval.emplace_back(std::string("ClosureFrame")); - - auto ids = SerializeIDList(outer_ids); - if ( ! ids ) - return broker::ec::invalid_data; - - rval.emplace_back(*ids); - - auto serialized = closure->SerializeClosureFrame(them); - if ( ! serialized ) - return broker::ec::invalid_data; - - rval.emplace_back(*serialized); - } - else - rval.emplace_back(std::string("Frame")); - - auto map = SerializeOffsetMap(new_map); - if ( ! map ) - return broker::ec::invalid_data; - - rval.emplace_back(*map); - - broker::vector body; - - for ( int i = 0; i < size; ++i ) - body.emplace_back(broker::none()); - - for ( const auto& id : us ) - { - int location = id->Offset(); - - auto where = new_map.find(std::string(id->Name())); - if ( where != new_map.end() ) - location = where->second; - - const auto& val = frame[location].val; - - TypeTag tag = val->GetType()->Tag(); - - auto expected = Broker::detail::val_to_data(val.get()); - if ( ! expected ) - return broker::ec::invalid_data; - - broker::vector val_tuple{std::move(*expected), static_cast(tag)}; - body[location] = val_tuple; - } - - rval.emplace_back(body); - - return {std::move(rval)}; - } - broker::expected Frame::SerializeCopyFrame() { broker::vector rval; @@ -401,7 +137,7 @@ broker::expected Frame::SerializeCopyFrame() for ( int i = 0; i < size; ++i ) { - const auto& val = frame[i].val; + const auto& val = frame[i]; auto expected = Broker::detail::val_to_data(val.get()); if ( ! expected ) return broker::ec::invalid_data; @@ -430,133 +166,16 @@ std::pair Frame::Unserialize(const broker::vector& data, std::advance(where, 1); - if ( captures || *has_name == "CopyFrame" ) - { - if ( captures ) - ASSERT(*has_name == "CopyFrame"); - - auto has_body = broker::get_if(*where); - if ( ! has_body ) - return std::make_pair(false, nullptr); - - broker::vector body = *has_body; - int frame_size = body.size(); - auto rf = make_intrusive(frame_size, nullptr, nullptr); - - rf->closure = nullptr; - - for ( int i = 0; i < frame_size; ++i ) - { - auto has_vec = broker::get_if(body[i]); - if ( ! has_vec ) - continue; - - broker::vector val_tuple = *has_vec; - if ( val_tuple.size() != 2 ) - return std::make_pair(false, nullptr); - - auto has_type = broker::get_if(val_tuple[1]); - if ( ! has_type ) - return std::make_pair(false, nullptr); - - broker::integer g = *has_type; - Type t(static_cast(g)); - - auto val = Broker::detail::data_to_val(std::move(val_tuple[0]), &t); - if ( ! val ) - return std::make_pair(false, nullptr); - - rf->frame[i].val = std::move(val); - } - - return std::make_pair(true, std::move(rf)); - } - - // Code to support deprecated semantics: - - IDPList outer_ids; - OffsetMap offset_map; - FramePtr closure; - - if ( *has_name == "ClosureFrame" ) - { - auto has_vec = broker::get_if(*where); - if ( ! has_vec ) - return std::make_pair(false, nullptr); - - std::advance(where, 1); - - auto list_pair = UnserializeIDList(*has_vec); - if ( ! list_pair.first ) - return std::make_pair(false, nullptr); - - outer_ids = std::move(list_pair.second); - - has_vec = broker::get_if(*where); - if ( ! has_vec ) - { - for ( auto& i : outer_ids ) - Unref(i); - - return std::make_pair(false, nullptr); - } - - std::advance(where, 1); - - auto closure_pair = Frame::Unserialize(*has_vec, {}); - if ( ! closure_pair.first ) - { - for ( auto& i : outer_ids ) - Unref(i); - - return std::make_pair(false, nullptr); - } - - closure = std::move(closure_pair.second); - } - - auto has_vec = broker::get_if(*where); - if ( ! has_vec ) - { - for ( auto& i : outer_ids ) - Unref(i); - - return std::make_pair(false, nullptr); - } - - std::advance(where, 1); - - auto map_pair = UnserializeOffsetMap(*has_vec); - if ( ! map_pair.first ) - { - for ( auto& i : outer_ids ) - Unref(i); - - return std::make_pair(false, nullptr); - } - - offset_map = std::move(map_pair.second); + if ( captures ) + ASSERT(*has_name == "CopyFrame"); auto has_body = broker::get_if(*where); if ( ! has_body ) - { - for ( auto& i : outer_ids ) - Unref(i); - return std::make_pair(false, nullptr); - } broker::vector body = *has_body; int frame_size = body.size(); - - // We'll associate this frame with a function later. auto rf = make_intrusive(frame_size, nullptr, nullptr); - rf->offset_map = std::make_unique(std::move(offset_map)); - - // Frame takes ownership of unref'ing elements in outer_ids - rf->outer_ids = std::move(outer_ids); - rf->closure = closure.release(); - rf->weak_closure_ref = false; for ( int i = 0; i < frame_size; ++i ) { @@ -579,45 +198,12 @@ std::pair Frame::Unserialize(const broker::vector& data, if ( ! val ) return std::make_pair(false, nullptr); - rf->frame[i].val = std::move(val); + rf->frame[i] = std::move(val); } return std::make_pair(true, std::move(rf)); } -void Frame::AddKnownOffsets(const IDPList& ids) - { - if ( ! offset_map ) - offset_map = std::make_unique(); - - std::transform(ids.begin(), ids.end(), std::inserter(*offset_map, offset_map->end()), - [](const ID* id) -> std::pair - { - return std::make_pair(std::string(id->Name()), id->Offset()); - }); - } - -void Frame::CaptureClosure(Frame* c, IDPList arg_outer_ids) - { - if ( closure || outer_ids.length() ) - reporter->InternalError("Attempted to override a closure."); - - outer_ids = std::move(arg_outer_ids); - - for ( auto& i : outer_ids ) - Ref(i); - - closure = c; - if ( closure ) - weak_closure_ref = true; - - /** - * Want to capture closures by copy? - * You'll also need to remove the Unref in the destructor. - */ - // if (c) closure = c->SelectiveClone(outer_ids); - } - const detail::Location* Frame::GetCallLocation() const { return call ? call->GetLocationInfo() : call_loc; @@ -633,111 +219,4 @@ void Frame::ClearTrigger() trigger = nullptr; } -void Frame::ClearElement(int n) - { - if ( frame[n].weak_ref ) - frame[n].val.release(); - else - frame[n] = {nullptr, false}; - } - -bool Frame::IsOuterID(const ID* in) const - { - return std::any_of(outer_ids.begin(), outer_ids.end(), - [&in](ID* id) -> bool - { - return strcmp(id->Name(), in->Name()) == 0; - }); - } - -broker::expected Frame::SerializeIDList(const IDPList& in) - { - broker::vector rval; - - for ( const auto& id : in ) - { - // name - rval.emplace_back(std::string(id->Name())); - // offset - rval.emplace_back(id->Offset()); - } - - return {std::move(rval)}; - } - -broker::expected Frame::SerializeOffsetMap(const OffsetMap& in) - { - broker::vector rval; - - std::for_each(in.begin(), in.end(), - [&rval](const std::pair& e) - { - rval.emplace_back(e.first); - rval.emplace_back(e.second); - }); - - return {std::move(rval)}; - } - -std::pair Frame::UnserializeIDList(const broker::vector& data) - { - IDPList rval; - if ( data.size() % 2 != 0 ) - return std::make_pair(false, std::move(rval)); - - auto where = data.begin(); - while ( where < data.end() ) - { - auto has_name = broker::get_if(*where); - if ( ! has_name ) - { - for ( auto& i : rval ) - Unref(i); - - rval = IDPList{}; - return std::make_pair(false, std::move(rval)); - } - - std::advance(where, 1); - - auto has_offset = broker::get_if(*where); - if ( ! has_offset ) - { - for ( auto& i : rval ) - Unref(i); - - rval = IDPList{}; - return std::make_pair(false, std::move(rval)); - } - - auto* id = new ID(has_name->c_str(), SCOPE_FUNCTION, false); - id->SetOffset(*has_offset); - rval.push_back(id); - std::advance(where, 1); - } - - return std::make_pair(true, std::move(rval)); - } - -std::pair> -Frame::UnserializeOffsetMap(const broker::vector& data) - { - OffsetMap rval; - - for ( broker::vector::size_type i = 0; i < data.size(); i += 2 ) - { - auto key = broker::get_if(data[i]); - if ( ! key ) - return std::make_pair(false, std::move(rval)); - - auto offset = broker::get_if(data[i + 1]); - if ( ! offset ) - return std::make_pair(false, std::move(rval)); - - rval.insert({std::move(*key), std::move(*offset)}); - } - - return std::make_pair(true, std::move(rval)); - } - } diff --git a/src/Frame.h b/src/Frame.h index 64944b7e3e..b56f547680 100644 --- a/src/Frame.h +++ b/src/Frame.h @@ -53,13 +53,6 @@ public: */ Frame(int size, const ScriptFunc* func, const zeek::Args* fn_args); - /** - * Deletes the frame. Unrefs its trigger (implicitly, since it's an - * IntrusivePtr), and the values that the frame contains and its - * closure if applicable. - */ - virtual ~Frame() override; - /** * @param n the index to get. * @return the value at index *n* of the underlying array. @@ -69,7 +62,7 @@ public: // Note: technically this may want to adjust by current_offset, but // in practice, this method is never called from anywhere other than // function call invocation, where current_offset should be zero. - return frame[n].val; + return frame[n]; } /** @@ -158,59 +151,14 @@ public: bool BreakOnReturn() const { return break_on_return; } /** - * Performs a deep copy of all the values in the current frame. If - * the frame has a closure the returned frame captures that closure - * by reference. As such, performing a clone operation does not copy - * the values in the closure. + * Performs a deep copy of all the values in the current frame. * * @return a copy of this frame. */ Frame* Clone() const; /** - * Clones a Frame, only making copies of the values associated with - * the IDs in selection. Cloning a frame does not deep-copy its - * closure; instead it makes a new copy of the frame which Refs the - * closure and all the elements that it might use from that closure. - * - * Unlike a regular clone operation where cloning the closure is quite - * hard because of circular references, cloning the closure here is - * possible. See Frame.cc for more notes on this. - * - * @return A copy of the frame where all the values associated with - * *selection* have been cloned. All other values are made to be - * null. - */ - Frame* SelectiveClone(const IDPList& selection, ScriptFunc* func) const; - - /** - * Serializes the frame in the context of supporting the (deprecated) - * reference semantics for closures. This can be fairly non-trivial. - * If the frame itself has no closure then the serialized frame - * is a vector: - * - * [ "Frame", [offset_map] [serialized_values] ] - * - * where serialized_values are two-element vectors. A serialized_value - * has the result of calling broker::data_to_val on the value in the - * first index, and an integer representing that value's type in the - * second index. offset_map is a serialized version of the frame's - * offset_map. - * - * A reference-semantics frame with its own closure needs to - * (recursively) serialize more information: - * - * [ "ClosureFrame", [outer_ids], Serialize(closure), [offset_map], - * [serialized_values] ] - * - * @return the broker representation, or an error if the serialization - * failed. - */ - broker::expected SerializeClosureFrame(const IDPList& selection); - - /** - * Serializes the frame in the context of supporting copy semantics - * for lambdas: + * Serializes the frame in support of copy semantics for lambdas: * * [ "CopyFrame", serialized_values ] * @@ -235,23 +183,6 @@ public: static std::pair Unserialize(const broker::vector& data, const std::optional& captures); - /** - * Sets the IDs that the frame knows offsets for. These offsets will - * be used instead of any previously provided ones for future lookups - * of IDs in *ids*. - * - * @param ids the ids that the frame will intake. - */ - void AddKnownOffsets(const IDPList& ids); - - /** - * Captures *c* as this frame's closure and Refs all of the values - * corresponding to outer_ids in that closure. This also Refs *c* as - * the frame will unref it upon deconstruction. When calling this, - * the frame's closure must not have been set yet. - */ - void CaptureClosure(Frame* c, IDPList outer_ids); - // If the frame is run in the context of a trigger condition evaluation, // the trigger needs to be registered. void SetTrigger(trigger::TriggerPtr arg_trigger); @@ -274,74 +205,19 @@ public: void SetDelayed() { delayed = true; } bool HasDelayed() const { return delayed; } - /** - * Track a new function that refers to this frame for use as a closure. - * This frame's destructor will then upgrade that functions reference - * from weak to strong (by making a copy). The initial use of - * weak references prevents unbreakable circular references that - * otherwise cause memory leaks. - */ - void AddFunctionWithClosureRef(ScriptFunc* func); - private: using OffsetMap = std::unordered_map; - struct Element - { - ValPtr val; - // Weak reference is used to prevent circular reference memory leaks - // in lambdas/closures. - bool weak_ref; - }; + // This has a trivial form now, but used to hold additional + // information, which is why we abstract it away from just being + // a ValPtr. + using Element = ValPtr; const ValPtr& GetElementByID(const ID* id) const; - /** - * Sets the element at index *n* of the underlying array to *v*, but does - * not take ownership of a reference count to it. This method is used to - * break circular references between lambda functions and closure frames. - * @param n the index to set - * @param v the value to set it to (caller has not Ref'd and Frame will - * not Unref it) - */ - void SetElementWeak(int n, Val* v); - - /** - * Clone an element at an offset into other frame if not equal to a given - * function (in that case just assigna weak reference). Used to break - * circular references between lambda functions and closure frames. - */ - void CloneNonFuncElement(int offset, ScriptFunc* func, Frame* other) const; - - /** - * Resets the value at offset 'n' frame (by decrementing reference - * count if not a weak reference). - */ - void ClearElement(int n); - - /** Have we captured this id? Version for deprecated semantics. */ - bool IsOuterID(const ID* in) const; - - /** Have we captured this id? Version for current semantics. */ - bool IsCaptureID(const ID* in) const; - - /** Serializes an offset_map */ - static broker::expected SerializeOffsetMap(const OffsetMap& in); - - /** Serializes an IDPList */ - static broker::expected SerializeIDList(const IDPList& in); - - /** Unserializes an offset map. */ - static std::pair> - UnserializeOffsetMap(const broker::vector& data); - - /** Unserializes an IDPList. */ - static std::pair UnserializeIDList(const broker::vector& data); - /** The number of vals that can be stored in this frame. */ int size; - bool weak_closure_ref = false; bool break_before_next_stmt; bool break_on_return; bool delayed; @@ -356,29 +232,11 @@ private: */ int current_offset; - /** The enclosing frame of this frame. Used for reference semantics. */ - Frame* closure; - - /** ID's used in this frame from the enclosing frame, when using - * reference semantics (closure != nullptr). - */ - IDPList outer_ids; - - /** - * Maps ID names to offsets. Used if this frame is serialized - * to maintain proper offsets after being sent elsewhere. - */ - std::unique_ptr offset_map; - /** Frame used for captures (if any) with copy semantics. */ Frame* captures; /** Maps IDs to offsets into the "captures" frame. If the ID * isn't present, then it's not a capture. - * - * We keep this separate from offset_map to help ensure we don't - * confuse code from the deprecated semantics with the current - * semantics. */ const OffsetMap* captures_offset_map; @@ -396,8 +254,6 @@ private: const CallExpr* call = nullptr; const void* assoc = nullptr; const Location* call_loc = nullptr; // only needed if call is nil - - std::unique_ptr> functions_with_closure_frame_reference; }; } // namespace detail diff --git a/src/Func.cc b/src/Func.cc index 54cbfa1d4d..a4e1806c8b 100644 --- a/src/Func.cc +++ b/src/Func.cc @@ -318,9 +318,6 @@ ScriptFunc::ScriptFunc(std::string _name, FuncTypePtr ft, std::vector b ScriptFunc::~ScriptFunc() { - if ( ! weak_closure_ref ) - Unref(closure); - delete captures_frame; delete captures_offset_mapping; } @@ -358,9 +355,6 @@ ValPtr ScriptFunc::Invoke(zeek::Args* args, Frame* parent) const auto f = make_intrusive(frame_size, this, args); - if ( closure ) - f->CaptureClosure(closure, outer_ids); - // Hand down any trigger. if ( parent ) { @@ -586,71 +580,6 @@ void ScriptFunc::ReplaceBody(const StmtPtr& old_body, StmtPtr new_body) current_body = new_body; } -void ScriptFunc::AddClosure(IDPList ids, Frame* f) - { - if ( ! f ) - return; - - SetOuterIDs(std::move(ids)); - SetClosureFrame(f); - } - -bool ScriptFunc::StrengthenClosureReference(Frame* f) - { - if ( closure != f ) - return false; - - if ( ! weak_closure_ref ) - return false; - - closure = closure->SelectiveClone(outer_ids, this); - weak_closure_ref = false; - return true; - } - -bool ScriptFunc::HasCopySemantics() const - { - return type->GetCaptures().has_value(); - } - -void ScriptFunc::SetClosureFrame(Frame* f) - { - if ( closure ) - reporter->InternalError("Tried to override closure for ScriptFunc %s.", Name()); - - // Have to use weak references initially because otherwise Ref'ing the - // original frame creates a circular reference: the function holds a - // reference to the frame and the frame contains a reference to this - // function value. And we can't just do a shallow clone of the frame - // up front because the closure semantics in Zeek allow mutating - // the outer frame. - - closure = f; - weak_closure_ref = true; - f->AddFunctionWithClosureRef(this); - } - -bool ScriptFunc::UpdateClosure(const broker::vector& data) - { - auto result = Frame::Unserialize(data, {}); - - if ( ! result.first ) - return false; - - auto& new_closure = result.second; - - if ( new_closure ) - new_closure->SetFunction(this); - - if ( ! weak_closure_ref ) - Unref(closure); - - weak_closure_ref = false; - closure = new_closure.release(); - - return true; - } - bool ScriptFunc::DeserializeCaptures(const broker::vector& data) { auto result = Frame::Unserialize(data, GetType()->GetCaptures()); @@ -671,8 +600,6 @@ FuncPtr ScriptFunc::DoClone() CopyStateInto(other.get()); other->frame_size = frame_size; - other->closure = closure ? closure->SelectiveClone(outer_ids, this) : nullptr; - other->weak_closure_ref = false; other->outer_ids = outer_ids; if ( captures_frame ) @@ -685,15 +612,12 @@ FuncPtr ScriptFunc::DoClone() return other; } -broker::expected ScriptFunc::SerializeClosure() const +broker::expected ScriptFunc::SerializeCaptures() const { if ( captures_frame ) return captures_frame->SerializeCopyFrame(); - if ( closure ) - return closure->SerializeClosureFrame(outer_ids); - - // No captures/closures, return an empty vector. + // No captures, return an empty vector. return broker::vector{}; } diff --git a/src/Func.h b/src/Func.h index 7d89f88609..567e60944f 100644 --- a/src/Func.h +++ b/src/Func.h @@ -182,42 +182,12 @@ public: */ const OffsetMap* GetCapturesOffsetMap() const { return captures_offset_mapping; } - // The following "Closure" methods implement the deprecated - // capture-by-reference functionality. - /** - * Adds a closure to the function. Closures are cloned and - * future calls to ScriptFunc methods will not modify *f*. + * Serializes this function's capture frame. * - * @param ids IDs that are captured by the closure. - * @param f the closure to be captured. + * @return a serialized version of the function's capture frame. */ - void AddClosure(IDPList 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); - - /** - * Whether the function's closure uses copy semantics. - */ - virtual bool HasCopySemantics() const; - - /** - * Serializes this function's closure or capture frame. - * - * @return a serialized version of the function's closure/capture frame. - */ - virtual broker::expected SerializeClosure() const; + virtual broker::expected SerializeCaptures() const; /** * Sets the captures frame to one built from *data*. @@ -267,18 +237,10 @@ protected: StmtPtr AddInits(StmtPtr body, const std::vector& inits); /** - * Clones this function along with its closures. + * Clones this function along with its captures. */ FuncPtr 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); - /** * Uses the given frame for captures, and generates the * mapping from captured variables to offsets in the frame. @@ -293,13 +255,7 @@ private: // List of the outer IDs used in the function. IDPList outer_ids; - // The following is used for deprecated capture-by-reference - // closures: - // The frame the ScriptFunc was initialized in. - Frame* closure = nullptr; - bool weak_closure_ref = false; - - // Used for capture-by-copy closures. These persist over the + // Frame for (capture-by-copy) closures. These persist over the // function's lifetime, providing quasi-globals that maintain // state across individual calls to the function. Frame* captures_frame = nullptr; diff --git a/src/Var.cc b/src/Var.cc index 3527054fd1..6110ea4ba9 100644 --- a/src/Var.cc +++ b/src/Var.cc @@ -745,16 +745,12 @@ TraversalCode OuterIDBindingFinder::PreStmt(const Stmt* stmt) if ( stmt->Tag() != STMT_WHEN ) return TC_CONTINUE; - auto ws = static_cast(stmt); - auto lambda = ws->Info()->Lambda(); - - if ( ! lambda ) - // Old-style semantics. - return TC_CONTINUE; - // The semantics of identifiers for the "when" statement are those // of the lambda it's transformed into. - lambda->Traverse(this); + + auto ws = static_cast(stmt); + ws->Info()->Lambda()->Traverse(this); + return TC_ABORTSTMT; } diff --git a/src/broker/Data.cc b/src/broker/Data.cc index b0b367f8fb..ec001045c9 100644 --- a/src/broker/Data.cc +++ b/src/broker/Data.cc @@ -417,20 +417,8 @@ struct val_converter return nullptr; auto* b = dynamic_cast(rval->AsFunc()); - if ( ! b ) + if ( ! b || ! b->DeserializeCaptures(*frame) ) return nullptr; - - if ( b->HasCopySemantics() ) - { - if ( ! b->DeserializeCaptures(*frame) ) - return nullptr; - } - else - { - // Support for deprecated serialization. - if ( ! b->UpdateClosure(*frame) ) - return nullptr; - } } return rval; @@ -906,7 +894,7 @@ broker::expected val_to_data(const Val* v) // Only ScriptFuncs have closures. if ( auto b = dynamic_cast(f) ) { - auto bc = b->SerializeClosure(); + auto bc = b->SerializeCaptures(); if ( ! bc ) return broker::ec::invalid_data; diff --git a/src/script_opt/CPP/Func.cc b/src/script_opt/CPP/Func.cc index 96f767d762..cd173c7332 100644 --- a/src/script_opt/CPP/Func.cc +++ b/src/script_opt/CPP/Func.cc @@ -29,7 +29,7 @@ CPPLambdaFunc::CPPLambdaFunc(string _name, FuncTypePtr ft, CPPStmtPtr _l_body) l_body = move(_l_body); } -broker::expected CPPLambdaFunc::SerializeClosure() const +broker::expected CPPLambdaFunc::SerializeCaptures() const { auto vals = l_body->SerializeLambdaCaptures(); diff --git a/src/script_opt/CPP/Func.h b/src/script_opt/CPP/Func.h index 28b348d62b..ece8380815 100644 --- a/src/script_opt/CPP/Func.h +++ b/src/script_opt/CPP/Func.h @@ -85,11 +85,9 @@ class CPPLambdaFunc : public ScriptFunc public: CPPLambdaFunc(std::string name, FuncTypePtr ft, CPPStmtPtr l_body); - bool HasCopySemantics() const override { return true; } - protected: // Methods related to sending lambdas via Broker. - broker::expected SerializeClosure() const override; + broker::expected SerializeCaptures() const override; void SetCaptures(Frame* f) override; FuncPtr DoClone() override; diff --git a/src/script_opt/ZAM/AM-Opt.cc b/src/script_opt/ZAM/AM-Opt.cc index 666fbe1292..461c02f6fb 100644 --- a/src/script_opt/ZAM/AM-Opt.cc +++ b/src/script_opt/ZAM/AM-Opt.cc @@ -800,16 +800,9 @@ void ZAMCompiler::CheckSlotUse(int slot, const ZInstI* inst) void ZAMCompiler::ExtendLifetime(int slot, const ZInstI* inst) { - // When using old-style lambda closure semantics, a function that - // returns a lambda needs to stick around for calls to that lambda. - // We ensure that by extending its lifetime to the end of this - // function. auto id = frame_denizens[slot]; auto& t = id->GetType(); - if ( t->Tag() == TYPE_FUNC && t->Yield() && t->Yield()->Tag() == TYPE_FUNC ) - inst = insts1.back(); - if ( denizen_ending.count(slot) > 0 ) { // End of denizen's lifetime already seen. Check for diff --git a/testing/btest/Baseline.cpp/language.closure-binding-deprecated/out b/testing/btest/Baseline.cpp/language.closure-binding-deprecated/out deleted file mode 100644 index 8466d969eb..0000000000 --- a/testing/btest/Baseline.cpp/language.closure-binding-deprecated/out +++ /dev/null @@ -1,12 +0,0 @@ -### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -reference capture -4, 10 -5, 8 -6, 7 -reference double capture -4 -2, 10, 47 -5 -3, 8, 47 -6 -4, 7, 47 diff --git a/testing/btest/Baseline.cpp/language.closure-sending-deprecated/recv.recv.out b/testing/btest/Baseline.cpp/language.closure-sending-deprecated/recv.recv.out deleted file mode 100644 index 4760591c3c..0000000000 --- a/testing/btest/Baseline.cpp/language.closure-sending-deprecated/recv.recv.out +++ /dev/null @@ -1,27 +0,0 @@ -### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -hello :-) -peer added -receiver got ping: function 2 -inside: 1 | outside: 11 | global: 100 -77 -receiver got ping: function 1 -begin: 100 | base_step: 2 -begin: 100 | base_step: 2 | step: 76 -178 -receiver got ping: function 2 -inside: 3 | outside: 11 | global: 100 -79 -receiver got ping: function 1 -begin: 100 | base_step: 4 -begin: 100 | base_step: 4 | step: 76 -180 -receiver got ping: function 2 -inside: 5 | outside: 11 | global: 100 -81 -receiver got ping: function 1 -begin: 100 | base_step: 6 -begin: 100 | base_step: 6 | step: 76 -182 -receiver got ping: function 2 -inside: 7 | outside: 11 | global: 100 -83 diff --git a/testing/btest/Baseline.cpp/language.closure-sending-deprecated/send.send.out b/testing/btest/Baseline.cpp/language.closure-sending-deprecated/send.send.out deleted file mode 100644 index 1d644231bc..0000000000 --- a/testing/btest/Baseline.cpp/language.closure-sending-deprecated/send.send.out +++ /dev/null @@ -1,32 +0,0 @@ -### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -hello :) -peer added -begin: 100 | base_step: 50 -sender got pong: function 2 -inside: 1 | outside: 11 | global: 10 -77 -begin: 100 | base_step: 50 -sender got pong: function 1 -begin: 100 | base_step: 2 -begin: 100 | base_step: 2 | step: 76 -178 -begin: 100 | base_step: 50 -sender got pong: function 2 -inside: 3 | outside: 11 | global: 10 -79 -begin: 100 | base_step: 50 -sender got pong: function 1 -begin: 100 | base_step: 4 -begin: 100 | base_step: 4 | step: 76 -180 -begin: 100 | base_step: 50 -sender got pong: function 2 -inside: 5 | outside: 11 | global: 10 -81 -begin: 100 | base_step: 50 -sender got pong: function 1 -begin: 100 | base_step: 6 -begin: 100 | base_step: 6 | step: 76 -182 -begin: 100 | base_step: 50 -peer lost diff --git a/testing/btest/Baseline/language.closure-binding-deprecated/out b/testing/btest/Baseline/language.closure-binding-deprecated/out deleted file mode 100644 index 066ca90cec..0000000000 --- a/testing/btest/Baseline/language.closure-binding-deprecated/out +++ /dev/null @@ -1,12 +0,0 @@ -### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -reference capture -4, 10 -6, 8 -7, 7 -reference double capture -4 -2, 10, 47 -4 -2, 8, 47 -3 -1, 7, 47 diff --git a/testing/btest/Baseline/language.closure-binding-errors/.stderr b/testing/btest/Baseline/language.closure-binding-errors/.stderr index 1b82c68894..45bda39df5 100644 --- a/testing/btest/Baseline/language.closure-binding-errors/.stderr +++ b/testing/btest/Baseline/language.closure-binding-errors/.stderr @@ -2,7 +2,6 @@ error in <...>/closure-binding-errors.zeek, line 12: a is captured but not used inside lambda (function(){ print no a!}) error in <...>/closure-binding-errors.zeek, line 13: no such local identifier: a2 error in <...>/closure-binding-errors.zeek, line 14: b is used inside lambda but not captured (function(){ print b}) -error in <...>/closure-binding-errors.zeek, line 14: a is captured but not used inside lambda (function(){ print b}) error in <...>/closure-binding-errors.zeek, line 15: a is captured but not used inside lambda (function(){ print b}) error in <...>/closure-binding-errors.zeek, line 16: b listed multiple times in capture (function(){ print b}) error in <...>/closure-binding-errors.zeek, line 18: cannot specify global in capture: c diff --git a/testing/btest/Baseline/language.closure-sending-deprecated/recv.recv.out b/testing/btest/Baseline/language.closure-sending-deprecated/recv.recv.out deleted file mode 100644 index d48a41b96d..0000000000 --- a/testing/btest/Baseline/language.closure-sending-deprecated/recv.recv.out +++ /dev/null @@ -1,27 +0,0 @@ -### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -hello :-) -peer added -receiver got ping: function 2 -inside: 1 | outside: 12 | global: 100 -77 -receiver got ping: function 1 -begin: 100 | base_step: 2 -begin: 100 | base_step: 2 | step: 76 -178 -receiver got ping: function 2 -inside: 3 | outside: 12 | global: 100 -79 -receiver got ping: function 1 -begin: 100 | base_step: 4 -begin: 100 | base_step: 4 | step: 76 -180 -receiver got ping: function 2 -inside: 5 | outside: 12 | global: 100 -81 -receiver got ping: function 1 -begin: 100 | base_step: 6 -begin: 100 | base_step: 6 | step: 76 -182 -receiver got ping: function 2 -inside: 7 | outside: 12 | global: 100 -83 diff --git a/testing/btest/Baseline/language.closure-sending-deprecated/send.send.out b/testing/btest/Baseline/language.closure-sending-deprecated/send.send.out deleted file mode 100644 index 39d70d48d5..0000000000 --- a/testing/btest/Baseline/language.closure-sending-deprecated/send.send.out +++ /dev/null @@ -1,32 +0,0 @@ -### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -hello :) -peer added -begin: 100 | base_step: 50 -sender got pong: function 2 -inside: 1 | outside: 12 | global: 10 -77 -begin: 100 | base_step: 50 -sender got pong: function 1 -begin: 178 | base_step: 2 -begin: 178 | base_step: 2 | step: 76 -256 -begin: 100 | base_step: 50 -sender got pong: function 2 -inside: 3 | outside: 12 | global: 10 -79 -begin: 100 | base_step: 50 -sender got pong: function 1 -begin: 180 | base_step: 4 -begin: 180 | base_step: 4 | step: 76 -260 -begin: 100 | base_step: 50 -sender got pong: function 2 -inside: 5 | outside: 12 | global: 10 -81 -begin: 100 | base_step: 50 -sender got pong: function 1 -begin: 182 | base_step: 6 -begin: 182 | base_step: 6 | step: 76 -264 -begin: 100 | base_step: 50 -peer lost diff --git a/testing/btest/language/closure-binding-deprecated.zeek b/testing/btest/language/closure-binding-deprecated.zeek deleted file mode 100644 index 90a5c7e78f..0000000000 --- a/testing/btest/language/closure-binding-deprecated.zeek +++ /dev/null @@ -1,47 +0,0 @@ -# @TEST-EXEC: zeek -b %INPUT >out -# @TEST-EXEC: btest-diff out - -type mutable_aggregate: record { x: count; }; - -function reference_capture() : function() - { - local a = 3; - local b = mutable_aggregate($x=11); - local f = function() { print ++a, --b$x; }; - f(); - ++a; - --b$x; - f(); - - return f; - } - -function reference_capture_double() : function() : function() - { - local a = 3; - local b = mutable_aggregate($x=11); - local f = function() : function() { - local c = mutable_aggregate($x=88); - print ++a; - local f2 = function() { print a -= 2, --b$x, c$x += 3; }; - c$x = c$x / 2; - return f2; - }; - f()(); - ++a; - --b$x; - f()(); - - return f; - } - -event zeek_init() - { - print "reference capture"; - local rc = reference_capture(); - rc(); - - print "reference double capture"; - local rc2 = reference_capture_double(); - rc2()(); - } diff --git a/testing/btest/language/closure-sending-deprecated.zeek b/testing/btest/language/closure-sending-deprecated.zeek deleted file mode 100644 index 987d9ae0ac..0000000000 --- a/testing/btest/language/closure-sending-deprecated.zeek +++ /dev/null @@ -1,167 +0,0 @@ -# @TEST-PORT: BROKER_PORT -# -# @TEST-EXEC: btest-bg-run recv "zeek -D -b ../recv.zeek >recv.out" -# @TEST-EXEC: btest-bg-run send "zeek -D -b ../send.zeek >send.out" -# -# @TEST-EXEC: btest-bg-wait 45 -# @TEST-EXEC: btest-diff recv/recv.out -# @TEST-EXEC: btest-diff send/send.out - -@TEST-START-FILE send.zeek - -redef exit_only_after_terminate = T; -type myfunctype: function(c: count) : function(d: count) : count; - -global global_with_same_name = 10; - -global ping: event(msg: string, f: myfunctype); - -event zeek_init() - { - print "hello :)"; - Broker::subscribe("zeek/event/my_topic"); - Broker::peer("127.0.0.1", to_port(getenv("BROKER_PORT"))); - } - -global n = 0; - -function send_event() - { - # in this frame event_count has an offset of three. - # in the receiving frame it has an offset of one. - # this tests to ensure that id lookups are being routed properly. - local dog = 0; - local not_dog = 1; - local event_count = 11; - - local log : myfunctype = function(c: count) : function(d: count) : count - { - print fmt("inside: %s | outside: %s | global: %s", c, event_count, global_with_same_name); - return function(d: count) : count { return d + c; }; - }; - - local two_part_adder_maker = function (begin : count) : function (base_step : count) : function ( step : count) : count - { - return function (base_step : count) : function (step : count) : count - { - print fmt("begin: %s | base_step: %s", begin, base_step); - return function (step : count) : count - { - print fmt("begin: %s | base_step: %s | step: %s", begin, base_step, step); - return (begin += base_step + step); }; }; }; - - local l = two_part_adder_maker(100); - local stepper = l(50); - - ++n; - ++event_count; - if ( n % 2 == 0) - { - local e2 = Broker::make_event(ping, "function 1", l); - Broker::publish("zeek/event/my_topic", e2); - } - else - { - local e = Broker::make_event(ping, "function 2", log); - Broker::publish("zeek/event/my_topic", e); - } - } - -event Broker::peer_added(endpoint: Broker::EndpointInfo, msg: string) - { - print "peer added"; - send_event(); - } - -event Broker::peer_lost(endpoint: Broker::EndpointInfo, msg: string) - { - print "peer lost"; - terminate(); - } - -event pong(msg: string, f: myfunctype) - { - print fmt("sender got pong: %s", msg); - local adder = f(n); - print adder(76); - send_event(); - } - -@TEST-END-FILE - -@TEST-START-FILE recv.zeek - -redef exit_only_after_terminate = T; -const events_to_recv = 7; -type myfunctype: function(c: count) : function(d: count) : count; -# type myfunctype: function(c: count); - -global global_with_same_name = 100; - -global pong: event(msg: string, f: myfunctype); - -# This is one, of many, ways to declare your functions that you plan to receive. -# All you are doing is giving the parser a version of their body, so they can be -# anywhere. This seems to work quite nicely because it keeps them scoped and stops -# them from ever being evaluated. -function my_funcs() - { - return; - - local begin = 100; - local event_count = begin; - - local l : myfunctype = function(c: count) : function(d: count) : count - { - print fmt("inside: %s | outside: %s | global: %s", c, event_count, global_with_same_name); - return function(d: count) : count { return d + c; }; - }; - - local dog_fish = function (base_step : count) : function (step : count) : count - { -# actual formatting doesn't matter for name resolution. -print fmt("begin: %s | base_step: %s", begin, base_step); - return function (step : count) : count - { - print fmt("begin: %s | base_step: %s | step: %s", begin, base_step, step); - return (begin += base_step + step); }; }; - } - -event zeek_init() - { - print "hello :-)"; - Broker::subscribe("zeek/event/my_topic"); - Broker::listen("127.0.0.1", to_port(getenv("BROKER_PORT"))); - } - -event Broker::peer_added(endpoint: Broker::EndpointInfo, msg: string) - { - print "peer added"; - } - -event Broker::peer_lost(endpoint: Broker::EndpointInfo, msg: string) - { - print "peer lost"; - } - -global n = 0; - -event ping(msg: string, f: myfunctype) - { - print fmt("receiver got ping: %s", msg); - ++n; - local adder = f(n); - print adder(76); - - if ( n == events_to_recv ) - { - terminate(); - } - else - { - local e = Broker::make_event(pong, msg, f); - Broker::publish("zeek/event/my_topic", e); - } - } - -@TEST-END-FILE