mirror of
https://github.com/zeek/zeek.git
synced 2025-10-07 17:18:20 +00:00
Merge remote-tracking branch 'origin/topic/vern/remove-deprecated-closures'
* origin/topic/vern/remove-deprecated-closures: removed deprecated capture-by-reference closures
This commit is contained in:
commit
9e953f50cb
22 changed files with 64 additions and 1221 deletions
4
CHANGES
4
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
|
5.1.0-dev.126 | 2022-06-27 11:43:27 -0700
|
||||||
|
|
||||||
* GH-2183: Rework Packet checksummed variable naming (Tim Wojtulewicz, Corelight)
|
* GH-2183: Rework Packet checksummed variable naming (Tim Wojtulewicz, Corelight)
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
5.1.0-dev.126
|
5.1.0-dev.128
|
||||||
|
|
40
src/Expr.cc
40
src/Expr.cc
|
@ -4702,7 +4702,11 @@ LambdaExpr::LambdaExpr(std::unique_ptr<function_ingredients> arg_ing, IDPList ar
|
||||||
|
|
||||||
SetType(ingredients->id->GetType());
|
SetType(ingredients->id->GetType());
|
||||||
|
|
||||||
CheckCaptures(when_parent);
|
if ( ! CheckCaptures(when_parent) )
|
||||||
|
{
|
||||||
|
SetError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Install a dummy version of the function globally for use only
|
// Install a dummy version of the function globally for use only
|
||||||
// when broker provides a closure.
|
// when broker provides a closure.
|
||||||
|
@ -4747,32 +4751,28 @@ LambdaExpr::LambdaExpr(std::unique_ptr<function_ingredients> arg_ing, IDPList ar
|
||||||
lambda_id->SetConst();
|
lambda_id->SetConst();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LambdaExpr::CheckCaptures(StmtPtr when_parent)
|
bool LambdaExpr::CheckCaptures(StmtPtr when_parent)
|
||||||
{
|
{
|
||||||
auto ft = type->AsFuncType();
|
auto ft = type->AsFuncType();
|
||||||
const auto& captures = ft->GetCaptures();
|
const auto& captures = ft->GetCaptures();
|
||||||
|
|
||||||
capture_by_ref = false;
|
auto desc = when_parent ? "\"when\" statement" : "lambda";
|
||||||
|
|
||||||
if ( ! captures )
|
if ( ! captures )
|
||||||
{
|
{
|
||||||
if ( outer_ids.size() > 0 )
|
if ( outer_ids.size() > 0 )
|
||||||
{
|
{
|
||||||
// TODO: Remove in v5.1: these deprecated closure semantics
|
reporter->Error("%s uses outer identifiers without [] captures: %s%s", desc,
|
||||||
reporter->Warning(
|
outer_ids.size() > 1 ? "e.g., " : "", outer_ids[0]->Name());
|
||||||
"use of outer identifiers in lambdas without [] captures is deprecated: %s%s",
|
return false;
|
||||||
outer_ids.size() > 1 ? "e.g., " : "", outer_ids[0]->Name());
|
|
||||||
capture_by_ref = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<const ID*> outer_is_matched;
|
std::set<const ID*> outer_is_matched;
|
||||||
std::set<const ID*> capture_is_matched;
|
std::set<const ID*> capture_is_matched;
|
||||||
|
|
||||||
auto desc = when_parent ? "\"when\" statement" : "lambda";
|
|
||||||
|
|
||||||
for ( const auto& c : *captures )
|
for ( const auto& c : *captures )
|
||||||
{
|
{
|
||||||
auto cid = c.id.get();
|
auto cid = c.id.get();
|
||||||
|
@ -4790,7 +4790,8 @@ void LambdaExpr::CheckCaptures(StmtPtr when_parent)
|
||||||
when_parent->Error(msg);
|
when_parent->Error(msg);
|
||||||
else
|
else
|
||||||
ExprError(msg);
|
ExprError(msg);
|
||||||
continue;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( auto id : outer_ids )
|
for ( auto id : outer_ids )
|
||||||
|
@ -4810,6 +4811,8 @@ void LambdaExpr::CheckCaptures(StmtPtr when_parent)
|
||||||
when_parent->Error(msg);
|
when_parent->Error(msg);
|
||||||
else
|
else
|
||||||
ExprError(msg);
|
ExprError(msg);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( const auto& c : *captures )
|
for ( const auto& c : *captures )
|
||||||
|
@ -4822,8 +4825,12 @@ void LambdaExpr::CheckCaptures(StmtPtr when_parent)
|
||||||
when_parent->Error(msg);
|
when_parent->Error(msg);
|
||||||
else
|
else
|
||||||
ExprError(msg);
|
ExprError(msg);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopePtr LambdaExpr::GetScope() const
|
ScopePtr LambdaExpr::GetScope() const
|
||||||
|
@ -4836,10 +4843,7 @@ ValPtr LambdaExpr::Eval(Frame* f) const
|
||||||
auto lamb = make_intrusive<ScriptFunc>(ingredients->id, ingredients->body, ingredients->inits,
|
auto lamb = make_intrusive<ScriptFunc>(ingredients->id, ingredients->body, ingredients->inits,
|
||||||
ingredients->frame_size, ingredients->priority);
|
ingredients->frame_size, ingredients->priority);
|
||||||
|
|
||||||
if ( capture_by_ref )
|
lamb->CreateCaptures(f);
|
||||||
lamb->AddClosure(outer_ids, f);
|
|
||||||
else
|
|
||||||
lamb->CreateCaptures(f);
|
|
||||||
|
|
||||||
// Set name to corresponding dummy func.
|
// Set name to corresponding dummy func.
|
||||||
// Allows for lookups by the receiver.
|
// Allows for lookups by the receiver.
|
||||||
|
@ -4856,6 +4860,10 @@ void LambdaExpr::ExprDescribe(ODesc* d) const
|
||||||
|
|
||||||
TraversalCode LambdaExpr::Traverse(TraversalCallback* cb) const
|
TraversalCode LambdaExpr::Traverse(TraversalCallback* cb) const
|
||||||
{
|
{
|
||||||
|
if ( IsError() )
|
||||||
|
// Not well-formed.
|
||||||
|
return TC_CONTINUE;
|
||||||
|
|
||||||
TraversalCode tc = cb->PreExpr(this);
|
TraversalCode tc = cb->PreExpr(this);
|
||||||
HANDLE_TC_EXPR_PRE(tc);
|
HANDLE_TC_EXPR_PRE(tc);
|
||||||
|
|
||||||
|
|
|
@ -1480,13 +1480,11 @@ protected:
|
||||||
void ExprDescribe(ODesc* d) const override;
|
void ExprDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CheckCaptures(StmtPtr when_parent);
|
bool CheckCaptures(StmtPtr when_parent);
|
||||||
|
|
||||||
std::unique_ptr<function_ingredients> ingredients;
|
std::unique_ptr<function_ingredients> ingredients;
|
||||||
IDPtr lambda_id;
|
IDPtr lambda_id;
|
||||||
|
|
||||||
IDPList outer_ids;
|
IDPList outer_ids;
|
||||||
bool capture_by_ref; // if true, use deprecated reference semantics
|
|
||||||
|
|
||||||
std::string my_name;
|
std::string my_name;
|
||||||
};
|
};
|
||||||
|
|
545
src/Frame.cc
545
src/Frame.cc
|
@ -30,8 +30,6 @@ Frame::Frame(int arg_size, const ScriptFunc* func, const zeek::Args* fn_args)
|
||||||
call = nullptr;
|
call = nullptr;
|
||||||
delayed = false;
|
delayed = false;
|
||||||
|
|
||||||
closure = nullptr;
|
|
||||||
|
|
||||||
// We could Ref()/Unref() the captures frame, but there's really
|
// We could Ref()/Unref() the captures frame, but there's really
|
||||||
// no need because by definition this current frame exists to
|
// no need because by definition this current frame exists to
|
||||||
// enable execution of the function, and its captures frame won't
|
// 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;
|
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<std::vector<ScriptFunc*>>();
|
|
||||||
|
|
||||||
functions_with_closure_frame_reference->emplace_back(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Frame::SetElement(int n, ValPtr v)
|
void Frame::SetElement(int n, ValPtr v)
|
||||||
{
|
{
|
||||||
n += current_offset;
|
n += current_offset;
|
||||||
|
frame[n] = std::move(v);
|
||||||
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};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Frame::SetElement(const ID* id, ValPtr v)
|
void Frame::SetElement(const ID* id, ValPtr v)
|
||||||
{
|
{
|
||||||
if ( closure && IsOuterID(id) )
|
|
||||||
{
|
|
||||||
closure->SetElement(id, std::move(v));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( captures )
|
if ( captures )
|
||||||
{
|
{
|
||||||
auto cap_off = captures_offset_map->find(id->Name());
|
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));
|
SetElement(id->Offset(), std::move(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
const ValPtr& Frame::GetElementByID(const ID* id) const
|
const ValPtr& Frame::GetElementByID(const ID* id) const
|
||||||
{
|
{
|
||||||
if ( closure && IsOuterID(id) )
|
|
||||||
return closure->GetElementByID(id);
|
|
||||||
|
|
||||||
if ( captures )
|
if ( captures )
|
||||||
{
|
{
|
||||||
auto cap_off = captures_offset_map->find(id->Name());
|
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);
|
return captures->GetElement(cap_off->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// do we have an offset for it?
|
return frame[id->Offset() + current_offset];
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Frame::Reset(int startIdx)
|
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 )
|
for ( int i = startIdx + current_offset; i < size; ++i )
|
||||||
ClearElement(i);
|
frame[i] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Frame::Describe(ODesc* d) const
|
void Frame::Describe(ODesc* d) const
|
||||||
|
@ -179,14 +90,14 @@ void Frame::Describe(ODesc* d) const
|
||||||
|
|
||||||
for ( int i = 0; i < size; ++i )
|
for ( int i = 0; i < size; ++i )
|
||||||
{
|
{
|
||||||
d->Add(frame[i].val != nullptr);
|
d->Add(frame[i] != nullptr);
|
||||||
d->SP();
|
d->SP();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( int i = 0; i < size; ++i )
|
for ( int i = 0; i < size; ++i )
|
||||||
if ( frame[i].val )
|
if ( frame[i] )
|
||||||
frame[i].val->Describe(d);
|
frame[i]->Describe(d);
|
||||||
else if ( d->IsReadable() )
|
else if ( d->IsReadable() )
|
||||||
d->Add("<nil>");
|
d->Add("<nil>");
|
||||||
}
|
}
|
||||||
|
@ -195,18 +106,13 @@ Frame* Frame::Clone() const
|
||||||
{
|
{
|
||||||
Frame* other = new Frame(size, function, func_args);
|
Frame* other = new Frame(size, function, func_args);
|
||||||
|
|
||||||
if ( offset_map )
|
|
||||||
other->offset_map = std::make_unique<OffsetMap>(*offset_map);
|
|
||||||
|
|
||||||
other->CaptureClosure(closure, outer_ids);
|
|
||||||
|
|
||||||
other->call = call;
|
other->call = call;
|
||||||
other->assoc = assoc;
|
other->assoc = assoc;
|
||||||
other->trigger = trigger;
|
other->trigger = trigger;
|
||||||
|
|
||||||
for ( int i = 0; i < size; i++ )
|
for ( int i = 0; i < size; i++ )
|
||||||
if ( frame[i].val )
|
if ( frame[i] )
|
||||||
other->frame[i].val = frame[i].val->Clone();
|
other->frame[i] = frame[i]->Clone();
|
||||||
|
|
||||||
// Note, there's no need to clone "captures" or "captures_offset_map"
|
// Note, there's no need to clone "captures" or "captures_offset_map"
|
||||||
// since those get created fresh when constructing "other".
|
// 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;
|
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<OffsetMap>(*offset_map);
|
|
||||||
else
|
|
||||||
*(other->offset_map) = *offset_map;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
other->offset_map.reset();
|
|
||||||
|
|
||||||
return other;
|
|
||||||
}
|
|
||||||
|
|
||||||
broker::expected<broker::data> 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<broker::integer>(tag)};
|
|
||||||
body[location] = val_tuple;
|
|
||||||
}
|
|
||||||
|
|
||||||
rval.emplace_back(body);
|
|
||||||
|
|
||||||
return {std::move(rval)};
|
|
||||||
}
|
|
||||||
|
|
||||||
broker::expected<broker::data> Frame::SerializeCopyFrame()
|
broker::expected<broker::data> Frame::SerializeCopyFrame()
|
||||||
{
|
{
|
||||||
broker::vector rval;
|
broker::vector rval;
|
||||||
|
@ -401,7 +137,7 @@ broker::expected<broker::data> Frame::SerializeCopyFrame()
|
||||||
|
|
||||||
for ( int i = 0; i < size; ++i )
|
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());
|
auto expected = Broker::detail::val_to_data(val.get());
|
||||||
if ( ! expected )
|
if ( ! expected )
|
||||||
return broker::ec::invalid_data;
|
return broker::ec::invalid_data;
|
||||||
|
@ -430,133 +166,16 @@ std::pair<bool, FramePtr> Frame::Unserialize(const broker::vector& data,
|
||||||
|
|
||||||
std::advance(where, 1);
|
std::advance(where, 1);
|
||||||
|
|
||||||
if ( captures || *has_name == "CopyFrame" )
|
if ( captures )
|
||||||
{
|
ASSERT(*has_name == "CopyFrame");
|
||||||
if ( captures )
|
|
||||||
ASSERT(*has_name == "CopyFrame");
|
|
||||||
|
|
||||||
auto has_body = broker::get_if<broker::vector>(*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>(frame_size, nullptr, nullptr);
|
|
||||||
|
|
||||||
rf->closure = nullptr;
|
|
||||||
|
|
||||||
for ( int i = 0; i < frame_size; ++i )
|
|
||||||
{
|
|
||||||
auto has_vec = broker::get_if<broker::vector>(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<broker::integer>(val_tuple[1]);
|
|
||||||
if ( ! has_type )
|
|
||||||
return std::make_pair(false, nullptr);
|
|
||||||
|
|
||||||
broker::integer g = *has_type;
|
|
||||||
Type t(static_cast<TypeTag>(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<broker::vector>(*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<broker::vector>(*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<broker::vector>(*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);
|
|
||||||
|
|
||||||
auto has_body = broker::get_if<broker::vector>(*where);
|
auto has_body = broker::get_if<broker::vector>(*where);
|
||||||
if ( ! has_body )
|
if ( ! has_body )
|
||||||
{
|
|
||||||
for ( auto& i : outer_ids )
|
|
||||||
Unref(i);
|
|
||||||
|
|
||||||
return std::make_pair(false, nullptr);
|
return std::make_pair(false, nullptr);
|
||||||
}
|
|
||||||
|
|
||||||
broker::vector body = *has_body;
|
broker::vector body = *has_body;
|
||||||
int frame_size = body.size();
|
int frame_size = body.size();
|
||||||
|
|
||||||
// We'll associate this frame with a function later.
|
|
||||||
auto rf = make_intrusive<Frame>(frame_size, nullptr, nullptr);
|
auto rf = make_intrusive<Frame>(frame_size, nullptr, nullptr);
|
||||||
rf->offset_map = std::make_unique<OffsetMap>(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 )
|
for ( int i = 0; i < frame_size; ++i )
|
||||||
{
|
{
|
||||||
|
@ -579,45 +198,12 @@ std::pair<bool, FramePtr> Frame::Unserialize(const broker::vector& data,
|
||||||
if ( ! val )
|
if ( ! val )
|
||||||
return std::make_pair(false, nullptr);
|
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));
|
return std::make_pair(true, std::move(rf));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Frame::AddKnownOffsets(const IDPList& ids)
|
|
||||||
{
|
|
||||||
if ( ! offset_map )
|
|
||||||
offset_map = std::make_unique<OffsetMap>();
|
|
||||||
|
|
||||||
std::transform(ids.begin(), ids.end(), std::inserter(*offset_map, offset_map->end()),
|
|
||||||
[](const ID* id) -> std::pair<std::string, int>
|
|
||||||
{
|
|
||||||
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
|
const detail::Location* Frame::GetCallLocation() const
|
||||||
{
|
{
|
||||||
return call ? call->GetLocationInfo() : call_loc;
|
return call ? call->GetLocationInfo() : call_loc;
|
||||||
|
@ -633,111 +219,4 @@ void Frame::ClearTrigger()
|
||||||
trigger = nullptr;
|
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<broker::data> 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<broker::data> Frame::SerializeOffsetMap(const OffsetMap& in)
|
|
||||||
{
|
|
||||||
broker::vector rval;
|
|
||||||
|
|
||||||
std::for_each(in.begin(), in.end(),
|
|
||||||
[&rval](const std::pair<std::string, int>& e)
|
|
||||||
{
|
|
||||||
rval.emplace_back(e.first);
|
|
||||||
rval.emplace_back(e.second);
|
|
||||||
});
|
|
||||||
|
|
||||||
return {std::move(rval)};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool, IDPList> 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<std::string>(*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<broker::integer>(*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<bool, std::unordered_map<std::string, int>>
|
|
||||||
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<std::string>(data[i]);
|
|
||||||
if ( ! key )
|
|
||||||
return std::make_pair(false, std::move(rval));
|
|
||||||
|
|
||||||
auto offset = broker::get_if<broker::integer>(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));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
158
src/Frame.h
158
src/Frame.h
|
@ -53,13 +53,6 @@ public:
|
||||||
*/
|
*/
|
||||||
Frame(int size, const ScriptFunc* func, const zeek::Args* fn_args);
|
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.
|
* @param n the index to get.
|
||||||
* @return the value at index *n* of the underlying array.
|
* @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
|
// Note: technically this may want to adjust by current_offset, but
|
||||||
// in practice, this method is never called from anywhere other than
|
// in practice, this method is never called from anywhere other than
|
||||||
// function call invocation, where current_offset should be zero.
|
// 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; }
|
bool BreakOnReturn() const { return break_on_return; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a deep copy of all the values in the current frame. If
|
* Performs a deep copy of all the values in the current frame.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* @return a copy of this frame.
|
* @return a copy of this frame.
|
||||||
*/
|
*/
|
||||||
Frame* Clone() const;
|
Frame* Clone() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clones a Frame, only making copies of the values associated with
|
* Serializes the frame in support of copy semantics for lambdas:
|
||||||
* 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<broker::data> SerializeClosureFrame(const IDPList& selection);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes the frame in the context of supporting copy semantics
|
|
||||||
* for lambdas:
|
|
||||||
*
|
*
|
||||||
* [ "CopyFrame", serialized_values ]
|
* [ "CopyFrame", serialized_values ]
|
||||||
*
|
*
|
||||||
|
@ -235,23 +183,6 @@ public:
|
||||||
static std::pair<bool, FramePtr>
|
static std::pair<bool, FramePtr>
|
||||||
Unserialize(const broker::vector& data, const std::optional<FuncType::CaptureList>& captures);
|
Unserialize(const broker::vector& data, const std::optional<FuncType::CaptureList>& 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,
|
// If the frame is run in the context of a trigger condition evaluation,
|
||||||
// the trigger needs to be registered.
|
// the trigger needs to be registered.
|
||||||
void SetTrigger(trigger::TriggerPtr arg_trigger);
|
void SetTrigger(trigger::TriggerPtr arg_trigger);
|
||||||
|
@ -274,74 +205,19 @@ public:
|
||||||
void SetDelayed() { delayed = true; }
|
void SetDelayed() { delayed = true; }
|
||||||
bool HasDelayed() const { return delayed; }
|
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:
|
private:
|
||||||
using OffsetMap = std::unordered_map<std::string, int>;
|
using OffsetMap = std::unordered_map<std::string, int>;
|
||||||
|
|
||||||
struct Element
|
// This has a trivial form now, but used to hold additional
|
||||||
{
|
// information, which is why we abstract it away from just being
|
||||||
ValPtr val;
|
// a ValPtr.
|
||||||
// Weak reference is used to prevent circular reference memory leaks
|
using Element = ValPtr;
|
||||||
// in lambdas/closures.
|
|
||||||
bool weak_ref;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ValPtr& GetElementByID(const ID* id) const;
|
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<broker::data> SerializeOffsetMap(const OffsetMap& in);
|
|
||||||
|
|
||||||
/** Serializes an IDPList */
|
|
||||||
static broker::expected<broker::data> SerializeIDList(const IDPList& in);
|
|
||||||
|
|
||||||
/** Unserializes an offset map. */
|
|
||||||
static std::pair<bool, std::unordered_map<std::string, int>>
|
|
||||||
UnserializeOffsetMap(const broker::vector& data);
|
|
||||||
|
|
||||||
/** Unserializes an IDPList. */
|
|
||||||
static std::pair<bool, IDPList> UnserializeIDList(const broker::vector& data);
|
|
||||||
|
|
||||||
/** The number of vals that can be stored in this frame. */
|
/** The number of vals that can be stored in this frame. */
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
bool weak_closure_ref = false;
|
|
||||||
bool break_before_next_stmt;
|
bool break_before_next_stmt;
|
||||||
bool break_on_return;
|
bool break_on_return;
|
||||||
bool delayed;
|
bool delayed;
|
||||||
|
@ -356,29 +232,11 @@ private:
|
||||||
*/
|
*/
|
||||||
int current_offset;
|
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<OffsetMap> offset_map;
|
|
||||||
|
|
||||||
/** Frame used for captures (if any) with copy semantics. */
|
/** Frame used for captures (if any) with copy semantics. */
|
||||||
Frame* captures;
|
Frame* captures;
|
||||||
|
|
||||||
/** Maps IDs to offsets into the "captures" frame. If the ID
|
/** Maps IDs to offsets into the "captures" frame. If the ID
|
||||||
* isn't present, then it's not a capture.
|
* 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;
|
const OffsetMap* captures_offset_map;
|
||||||
|
|
||||||
|
@ -396,8 +254,6 @@ private:
|
||||||
const CallExpr* call = nullptr;
|
const CallExpr* call = nullptr;
|
||||||
const void* assoc = nullptr;
|
const void* assoc = nullptr;
|
||||||
const Location* call_loc = nullptr; // only needed if call is nil
|
const Location* call_loc = nullptr; // only needed if call is nil
|
||||||
|
|
||||||
std::unique_ptr<std::vector<ScriptFunc*>> functions_with_closure_frame_reference;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
80
src/Func.cc
80
src/Func.cc
|
@ -318,9 +318,6 @@ ScriptFunc::ScriptFunc(std::string _name, FuncTypePtr ft, std::vector<StmtPtr> b
|
||||||
|
|
||||||
ScriptFunc::~ScriptFunc()
|
ScriptFunc::~ScriptFunc()
|
||||||
{
|
{
|
||||||
if ( ! weak_closure_ref )
|
|
||||||
Unref(closure);
|
|
||||||
|
|
||||||
delete captures_frame;
|
delete captures_frame;
|
||||||
delete captures_offset_mapping;
|
delete captures_offset_mapping;
|
||||||
}
|
}
|
||||||
|
@ -358,9 +355,6 @@ ValPtr ScriptFunc::Invoke(zeek::Args* args, Frame* parent) const
|
||||||
|
|
||||||
auto f = make_intrusive<Frame>(frame_size, this, args);
|
auto f = make_intrusive<Frame>(frame_size, this, args);
|
||||||
|
|
||||||
if ( closure )
|
|
||||||
f->CaptureClosure(closure, outer_ids);
|
|
||||||
|
|
||||||
// Hand down any trigger.
|
// Hand down any trigger.
|
||||||
if ( parent )
|
if ( parent )
|
||||||
{
|
{
|
||||||
|
@ -586,71 +580,6 @@ void ScriptFunc::ReplaceBody(const StmtPtr& old_body, StmtPtr new_body)
|
||||||
current_body = 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)
|
bool ScriptFunc::DeserializeCaptures(const broker::vector& data)
|
||||||
{
|
{
|
||||||
auto result = Frame::Unserialize(data, GetType()->GetCaptures());
|
auto result = Frame::Unserialize(data, GetType()->GetCaptures());
|
||||||
|
@ -671,8 +600,6 @@ FuncPtr ScriptFunc::DoClone()
|
||||||
CopyStateInto(other.get());
|
CopyStateInto(other.get());
|
||||||
|
|
||||||
other->frame_size = frame_size;
|
other->frame_size = frame_size;
|
||||||
other->closure = closure ? closure->SelectiveClone(outer_ids, this) : nullptr;
|
|
||||||
other->weak_closure_ref = false;
|
|
||||||
other->outer_ids = outer_ids;
|
other->outer_ids = outer_ids;
|
||||||
|
|
||||||
if ( captures_frame )
|
if ( captures_frame )
|
||||||
|
@ -685,15 +612,12 @@ FuncPtr ScriptFunc::DoClone()
|
||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
|
|
||||||
broker::expected<broker::data> ScriptFunc::SerializeClosure() const
|
broker::expected<broker::data> ScriptFunc::SerializeCaptures() const
|
||||||
{
|
{
|
||||||
if ( captures_frame )
|
if ( captures_frame )
|
||||||
return captures_frame->SerializeCopyFrame();
|
return captures_frame->SerializeCopyFrame();
|
||||||
|
|
||||||
if ( closure )
|
// No captures, return an empty vector.
|
||||||
return closure->SerializeClosureFrame(outer_ids);
|
|
||||||
|
|
||||||
// No captures/closures, return an empty vector.
|
|
||||||
return broker::vector{};
|
return broker::vector{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
54
src/Func.h
54
src/Func.h
|
@ -182,42 +182,12 @@ public:
|
||||||
*/
|
*/
|
||||||
const OffsetMap* GetCapturesOffsetMap() const { return captures_offset_mapping; }
|
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
|
* Serializes this function's capture frame.
|
||||||
* future calls to ScriptFunc methods will not modify *f*.
|
|
||||||
*
|
*
|
||||||
* @param ids IDs that are captured by the closure.
|
* @return a serialized version of the function's capture frame.
|
||||||
* @param f the closure to be captured.
|
|
||||||
*/
|
*/
|
||||||
void AddClosure(IDPList ids, Frame* f);
|
virtual broker::expected<broker::data> SerializeCaptures() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<broker::data> SerializeClosure() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the captures frame to one built from *data*.
|
* Sets the captures frame to one built from *data*.
|
||||||
|
@ -267,18 +237,10 @@ protected:
|
||||||
StmtPtr AddInits(StmtPtr body, const std::vector<IDPtr>& inits);
|
StmtPtr AddInits(StmtPtr body, const std::vector<IDPtr>& inits);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clones this function along with its closures.
|
* Clones this function along with its captures.
|
||||||
*/
|
*/
|
||||||
FuncPtr DoClone() override;
|
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
|
* Uses the given frame for captures, and generates the
|
||||||
* mapping from captured variables to offsets in the frame.
|
* mapping from captured variables to offsets in the frame.
|
||||||
|
@ -293,13 +255,7 @@ private:
|
||||||
// List of the outer IDs used in the function.
|
// List of the outer IDs used in the function.
|
||||||
IDPList outer_ids;
|
IDPList outer_ids;
|
||||||
|
|
||||||
// The following is used for deprecated capture-by-reference
|
// Frame for (capture-by-copy) closures. These persist over the
|
||||||
// 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
|
|
||||||
// function's lifetime, providing quasi-globals that maintain
|
// function's lifetime, providing quasi-globals that maintain
|
||||||
// state across individual calls to the function.
|
// state across individual calls to the function.
|
||||||
Frame* captures_frame = nullptr;
|
Frame* captures_frame = nullptr;
|
||||||
|
|
12
src/Var.cc
12
src/Var.cc
|
@ -745,16 +745,12 @@ TraversalCode OuterIDBindingFinder::PreStmt(const Stmt* stmt)
|
||||||
if ( stmt->Tag() != STMT_WHEN )
|
if ( stmt->Tag() != STMT_WHEN )
|
||||||
return TC_CONTINUE;
|
return TC_CONTINUE;
|
||||||
|
|
||||||
auto ws = static_cast<const WhenStmt*>(stmt);
|
|
||||||
auto lambda = ws->Info()->Lambda();
|
|
||||||
|
|
||||||
if ( ! lambda )
|
|
||||||
// Old-style semantics.
|
|
||||||
return TC_CONTINUE;
|
|
||||||
|
|
||||||
// The semantics of identifiers for the "when" statement are those
|
// The semantics of identifiers for the "when" statement are those
|
||||||
// of the lambda it's transformed into.
|
// of the lambda it's transformed into.
|
||||||
lambda->Traverse(this);
|
|
||||||
|
auto ws = static_cast<const WhenStmt*>(stmt);
|
||||||
|
ws->Info()->Lambda()->Traverse(this);
|
||||||
|
|
||||||
return TC_ABORTSTMT;
|
return TC_ABORTSTMT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -417,20 +417,8 @@ struct val_converter
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto* b = dynamic_cast<zeek::detail::ScriptFunc*>(rval->AsFunc());
|
auto* b = dynamic_cast<zeek::detail::ScriptFunc*>(rval->AsFunc());
|
||||||
if ( ! b )
|
if ( ! b || ! b->DeserializeCaptures(*frame) )
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if ( b->HasCopySemantics() )
|
|
||||||
{
|
|
||||||
if ( ! b->DeserializeCaptures(*frame) )
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Support for deprecated serialization.
|
|
||||||
if ( ! b->UpdateClosure(*frame) )
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rval;
|
return rval;
|
||||||
|
@ -906,7 +894,7 @@ broker::expected<broker::data> val_to_data(const Val* v)
|
||||||
// Only ScriptFuncs have closures.
|
// Only ScriptFuncs have closures.
|
||||||
if ( auto b = dynamic_cast<const zeek::detail::ScriptFunc*>(f) )
|
if ( auto b = dynamic_cast<const zeek::detail::ScriptFunc*>(f) )
|
||||||
{
|
{
|
||||||
auto bc = b->SerializeClosure();
|
auto bc = b->SerializeCaptures();
|
||||||
if ( ! bc )
|
if ( ! bc )
|
||||||
return broker::ec::invalid_data;
|
return broker::ec::invalid_data;
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ CPPLambdaFunc::CPPLambdaFunc(string _name, FuncTypePtr ft, CPPStmtPtr _l_body)
|
||||||
l_body = move(_l_body);
|
l_body = move(_l_body);
|
||||||
}
|
}
|
||||||
|
|
||||||
broker::expected<broker::data> CPPLambdaFunc::SerializeClosure() const
|
broker::expected<broker::data> CPPLambdaFunc::SerializeCaptures() const
|
||||||
{
|
{
|
||||||
auto vals = l_body->SerializeLambdaCaptures();
|
auto vals = l_body->SerializeLambdaCaptures();
|
||||||
|
|
||||||
|
|
|
@ -85,11 +85,9 @@ class CPPLambdaFunc : public ScriptFunc
|
||||||
public:
|
public:
|
||||||
CPPLambdaFunc(std::string name, FuncTypePtr ft, CPPStmtPtr l_body);
|
CPPLambdaFunc(std::string name, FuncTypePtr ft, CPPStmtPtr l_body);
|
||||||
|
|
||||||
bool HasCopySemantics() const override { return true; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Methods related to sending lambdas via Broker.
|
// Methods related to sending lambdas via Broker.
|
||||||
broker::expected<broker::data> SerializeClosure() const override;
|
broker::expected<broker::data> SerializeCaptures() const override;
|
||||||
void SetCaptures(Frame* f) override;
|
void SetCaptures(Frame* f) override;
|
||||||
|
|
||||||
FuncPtr DoClone() override;
|
FuncPtr DoClone() override;
|
||||||
|
|
|
@ -800,16 +800,9 @@ void ZAMCompiler::CheckSlotUse(int slot, const ZInstI* inst)
|
||||||
|
|
||||||
void ZAMCompiler::ExtendLifetime(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 id = frame_denizens[slot];
|
||||||
auto& t = id->GetType();
|
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 )
|
if ( denizen_ending.count(slot) > 0 )
|
||||||
{
|
{
|
||||||
// End of denizen's lifetime already seen. Check for
|
// End of denizen's lifetime already seen. Check for
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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 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 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: 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 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 16: b listed multiple times in capture (function(){ print b})
|
||||||
error in <...>/closure-binding-errors.zeek, line 18: cannot specify global in capture: c
|
error in <...>/closure-binding-errors.zeek, line 18: cannot specify global in capture: c
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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()();
|
|
||||||
}
|
|
|
@ -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
|
|
Loading…
Add table
Add a link
Reference in a new issue