Use vector<IntrusivePtr<Val>> for Func::Call and Event queuing args

This change may break BIFs that use @ARGS@, @ARG@, or @ARGC@ since their
types have changed.
This commit is contained in:
Jon Siwek 2020-03-20 18:03:04 -07:00
parent 94656c2308
commit 4e1ac4e124
29 changed files with 367 additions and 305 deletions

6
NEWS
View file

@ -27,10 +27,14 @@ Changed Functionality
---------------------
- Several C++ functions have been changed to pass smart pointers
(`class IntrusivePtr<>`) instead of raw pointers. This makes the
(``class IntrusivePtr<>``) instead of raw pointers. This makes the
code more robust. External plugins may need to be updated to this
API change.
- BIFs that use @ARG@, @ARGS@, or @ARGC@ may break since their type has
changed: BIF arguments are now passed as a ``std::vector<IntrusivePtr<Val>>``
rather than a ``val_list`` (i.e. ``List<Val*>``).
Removed Functionality
---------------------

@ -1 +1 @@
Subproject commit b3a5d01c041b78a9e50544ac891c5e0d35c116f7
Subproject commit 75f645ac9bdfd141f549b7e1a197459f2ad518be

View file

@ -282,6 +282,7 @@ set(MAIN_SRCS
Val.cc
Var.cc
WeirdState.cc
ZeekArgs.cc
bsd-getopt-long.c
bro_inet_ntop.c
cq.c

View file

@ -18,7 +18,7 @@ EventMgr mgr;
uint64_t num_events_queued = 0;
uint64_t num_events_dispatched = 0;
Event::Event(EventHandlerPtr arg_handler, val_list arg_args,
Event::Event(EventHandlerPtr arg_handler, zeek::Args arg_args,
SourceID arg_src, analyzer::ID arg_aid, TimerMgr* arg_mgr,
BroObj* arg_obj)
: handler(arg_handler),
@ -33,14 +33,6 @@ Event::Event(EventHandlerPtr arg_handler, val_list arg_args,
Ref(obj);
}
Event::Event(EventHandlerPtr arg_handler, val_list* arg_args,
SourceID arg_src, analyzer::ID arg_aid, TimerMgr* arg_mgr,
BroObj* arg_obj)
: Event(arg_handler, std::move(*arg_args), arg_src, arg_aid, arg_mgr, arg_obj)
{
delete arg_args;
}
void Event::Describe(ODesc* d) const
{
if ( d->IsReadable() )
@ -53,7 +45,7 @@ void Event::Describe(ODesc* d) const
if ( ! d->IsBinary() )
d->Add("(");
describe_vals(&args, d);
describe_vals(args, d);
if ( ! d->IsBinary() )
d->Add("(");
}
@ -68,7 +60,7 @@ void Event::Dispatch(bool no_remote)
try
{
handler->Call(&args, no_remote);
handler->Call(args, no_remote);
}
catch ( InterpreterException& e )
@ -106,12 +98,19 @@ EventMgr::~EventMgr()
Unref(src_val);
}
void EventMgr::QueueEventFast(const EventHandlerPtr &h, val_list vl,
SourceID src, analyzer::ID aid, TimerMgr* mgr,
BroObj* obj)
{
QueueEvent(new Event(h, zeek::val_list_to_args(&vl), src, aid, mgr, obj));
}
void EventMgr::QueueEvent(const EventHandlerPtr &h, val_list vl,
SourceID src, analyzer::ID aid,
TimerMgr* mgr, BroObj* obj)
{
if ( h )
QueueEvent(new Event(h, std::move(vl), src, aid, mgr, obj));
QueueEvent(new Event(h, zeek::val_list_to_args(&vl), src, aid, mgr, obj));
else
{
for ( const auto& v : vl )
@ -119,6 +118,29 @@ void EventMgr::QueueEvent(const EventHandlerPtr &h, val_list vl,
}
}
void EventMgr::QueueEvent(const EventHandlerPtr &h, val_list* vl,
SourceID src, analyzer::ID aid,
TimerMgr* mgr, BroObj* obj)
{
QueueEvent(h, std::move(*vl), src, aid, mgr, obj);
delete vl;
}
void EventMgr::QueueCheckedEvent(const EventHandlerPtr& h, zeek::Args vl,
SourceID src, analyzer::ID aid,
TimerMgr* mgr, BroObj* obj)
{
QueueEvent(new Event(h, std::move(vl), src, aid, mgr, obj));
}
void EventMgr::QueueUncheckedEvent(const EventHandlerPtr& h, zeek::Args vl,
SourceID src, analyzer::ID aid,
TimerMgr* mgr, BroObj* obj)
{
if ( h )
QueueEvent(new Event(h, std::move(vl), src, aid, mgr, obj));
}
void EventMgr::QueueEvent(Event* event)
{
bool done = PLUGIN_HOOK_WITH_RESULT(HOOK_QUEUE_EVENT, HookQueueEvent(event), false);

View file

@ -6,20 +6,15 @@
#include "analyzer/Analyzer.h"
#include "iosource/IOSource.h"
#include "Flare.h"
#include "ZeekArgs.h"
class EventMgr;
// We don't Unref() the individual arguments by using delete_vals()
// in a dtor because Func::Call already does that.
class Event : public BroObj {
public:
Event(EventHandlerPtr handler, val_list args,
Event(EventHandlerPtr handler, zeek::Args args,
SourceID src = SOURCE_LOCAL, analyzer::ID aid = 0,
TimerMgr* mgr = 0, BroObj* obj = 0);
Event(EventHandlerPtr handler, val_list* args,
SourceID src = SOURCE_LOCAL, analyzer::ID aid = 0,
TimerMgr* mgr = 0, BroObj* obj = 0);
TimerMgr* mgr = nullptr, BroObj* obj = nullptr);
void SetNext(Event* n) { next_event = n; }
Event* NextEvent() const { return next_event; }
@ -28,7 +23,7 @@ public:
analyzer::ID Analyzer() const { return aid; }
TimerMgr* Mgr() const { return mgr; }
EventHandlerPtr Handler() const { return handler; }
const val_list* Args() const { return &args; }
const zeek::Args& Args() const { return args; }
void Describe(ODesc* d) const override;
@ -40,7 +35,7 @@ protected:
void Dispatch(bool no_remote = false);
EventHandlerPtr handler;
val_list args;
zeek::Args args;
SourceID src;
analyzer::ID aid;
TimerMgr* mgr;
@ -64,12 +59,11 @@ public:
// against the case where there's no handlers (one usually also does that
// because it would be a waste of effort to construct all the event
// arguments when there's no handlers to consume them).
// TODO: deprecate
/* [[deprecated("Remove in v4.1. Use IntrusivePtr overload instead.")]] */
void QueueEventFast(const EventHandlerPtr &h, val_list vl,
SourceID src = SOURCE_LOCAL, analyzer::ID aid = 0,
TimerMgr* mgr = 0, BroObj* obj = 0)
{
QueueEvent(new Event(h, std::move(vl), src, aid, mgr, obj));
}
TimerMgr* mgr = 0, BroObj* obj = 0);
// Queues an event if there's an event handler (or remote consumer). This
// function always takes ownership of decrementing the reference count of
@ -77,6 +71,8 @@ public:
// checked for event handler existence, you may wish to call
// QueueEventFast() instead of this function to prevent the redundant
// existence check.
// TODO: deprecate
/* [[deprecated("Remove in v4.1. Use IntrusivePtr overload instead.")]] */
void QueueEvent(const EventHandlerPtr &h, val_list vl,
SourceID src = SOURCE_LOCAL, analyzer::ID aid = 0,
TimerMgr* mgr = 0, BroObj* obj = 0);
@ -85,13 +81,32 @@ public:
// pointer instead of by value. This function takes ownership of the
// memory pointed to by 'vl' as well as decrementing the reference count of
// each of its elements.
// TODO: deprecate
/* [[deprecated("Remove in v4.1. Use IntrusivePtr overload instead.")]] */
void QueueEvent(const EventHandlerPtr &h, val_list* vl,
SourceID src = SOURCE_LOCAL, analyzer::ID aid = 0,
TimerMgr* mgr = 0, BroObj* obj = 0)
{
QueueEvent(h, std::move(*vl), src, aid, mgr, obj);
delete vl;
}
TimerMgr* mgr = 0, BroObj* obj = 0);
/**
* Queues an event without first checking if there's an event handler
* remote consumer. If there are actually no handlers/consumers upon
* dispatching the event, nothing happens besides having wasted a bit of
* time and resources. This method is mostly useful from a performance
* standpoint: usually callers have already checked that the event will
* consumed so they don't waste time creating an argument list that will
* only be discarded, so there's no need to do the same check again when
* going to queue the event.
*/
void QueueUncheckedEvent(const EventHandlerPtr& h, zeek::Args vl,
SourceID src = SOURCE_LOCAL, analyzer::ID aid = 0,
TimerMgr* mgr = nullptr, BroObj* obj = nullptr);
/**
* Queues an event if it has an event handler or remote consumer.
*/
void QueueCheckedEvent(const EventHandlerPtr& h, zeek::Args vl,
SourceID src = SOURCE_LOCAL, analyzer::ID aid = 0,
TimerMgr* mgr = nullptr, BroObj* obj = nullptr);
void Dispatch(Event* event, bool no_remote = false);

View file

@ -60,7 +60,7 @@ void EventHandler::SetLocalHandler(Func* f)
local = f;
}
void EventHandler::Call(val_list* vl, bool no_remote)
void EventHandler::Call(const zeek::Args& vl, bool no_remote)
{
#ifdef PROFILE_BRO_FUNCTIONS
DEBUG_MSG("Event: %s\n", Name());
@ -75,12 +75,12 @@ void EventHandler::Call(val_list* vl, bool no_remote)
{
// Send event in form [name, xs...] where xs represent the arguments.
broker::vector xs;
xs.reserve(vl->length());
xs.reserve(vl.size());
bool valid_args = true;
for ( auto i = 0; i < vl->length(); ++i )
for ( auto i = 0u; i < vl.size(); ++i )
{
auto opt_data = bro_broker::val_to_data((*vl)[i]);
auto opt_data = bro_broker::val_to_data(vl[i].get());
if ( opt_data )
xs.emplace_back(move(*opt_data));
@ -115,14 +115,9 @@ void EventHandler::Call(val_list* vl, bool no_remote)
if ( local )
// No try/catch here; we pass exceptions upstream.
local->Call(vl);
else
{
for ( auto v : *vl )
Unref(v);
}
}
void EventHandler::NewEvent(val_list* vl)
void EventHandler::NewEvent(const zeek::Args& vl)
{
if ( ! new_event )
return;
@ -132,7 +127,7 @@ void EventHandler::NewEvent(val_list* vl)
return;
RecordType* args = FType()->Args();
VectorVal* vargs = new VectorVal(call_argument_vector);
auto vargs = make_intrusive<VectorVal>(call_argument_vector);
for ( int i = 0; i < args->NumFields(); i++ )
{
@ -151,19 +146,15 @@ void EventHandler::NewEvent(val_list* vl)
if ( fdefault )
rec->Assign(2, std::move(fdefault));
if ( i < vl->length() && (*vl)[i] )
{
Val* val = (*vl)[i];
Ref(val);
rec->Assign(3, val);
}
if ( i < static_cast<int>(vl.size()) && vl[i] )
rec->Assign(3, vl[i]);
vargs->Assign(i, std::move(rec));
}
Event* ev = new Event(new_event, {
new StringVal(name),
vargs,
make_intrusive<StringVal>(name),
std::move(vargs),
});
mgr.Dispatch(ev);
}

View file

@ -3,6 +3,7 @@
#pragma once
#include "BroList.h"
#include "ZeekArgs.h"
#include <unordered_set>
#include <string>
@ -31,7 +32,7 @@ public:
auto_publish.erase(topic);
}
void Call(val_list* vl, bool no_remote = false);
void Call(const zeek::Args& vl, bool no_remote = false);
// Returns true if there is at least one local or remote handler.
explicit operator bool() const;
@ -52,7 +53,7 @@ public:
bool GenerateAlways() { return generate_always; }
private:
void NewEvent(val_list* vl); // Raise new_event() meta event.
void NewEvent(const zeek::Args& vl); // Raise new_event() meta event.
const char* name;
Func* local;

View file

@ -3884,12 +3884,11 @@ IntrusivePtr<Val> FlattenExpr::Fold(Val* v) const
return l;
}
ScheduleTimer::ScheduleTimer(EventHandlerPtr arg_event, val_list* arg_args,
ScheduleTimer::ScheduleTimer(EventHandlerPtr arg_event, zeek::Args arg_args,
double t, TimerMgr* arg_tmgr)
: Timer(t, TIMER_SCHEDULE),
event(arg_event), args(std::move(*arg_args)), tmgr(arg_tmgr)
event(arg_event), args(std::move(arg_args)), tmgr(arg_tmgr)
{
delete arg_args;
}
ScheduleTimer::~ScheduleTimer()
@ -3898,7 +3897,7 @@ ScheduleTimer::~ScheduleTimer()
void ScheduleTimer::Dispatch(double /* t */, int /* is_expire */)
{
mgr.QueueEvent(event, std::move(args), SOURCE_LOCAL, 0, tmgr);
mgr.QueueUncheckedEvent(event, std::move(args), SOURCE_LOCAL, 0, tmgr);
}
ScheduleExpr::ScheduleExpr(IntrusivePtr<Expr> arg_when,
@ -3937,7 +3936,7 @@ IntrusivePtr<Val> ScheduleExpr::Eval(Frame* f) const
if ( when->Type()->Tag() == TYPE_INTERVAL )
dt += network_time;
val_list* args = eval_list(f, event->Args());
auto args = eval_list(f, event->Args());
if ( args )
{
@ -3946,7 +3945,7 @@ IntrusivePtr<Val> ScheduleExpr::Eval(Frame* f) const
if ( ! tmgr )
tmgr = timer_mgr;
tmgr->Add(new ScheduleTimer(event->Handler(), args, dt, tmgr));
tmgr->Add(new ScheduleTimer(event->Handler(), std::move(*args), dt, tmgr));
}
return nullptr;
@ -4236,7 +4235,7 @@ IntrusivePtr<Val> CallExpr::Eval(Frame* f) const
IntrusivePtr<Val> ret;
auto func_val = func->Eval(f);
val_list* v = eval_list(f, args.get());
auto v = eval_list(f, args.get());
if ( func_val && v )
{
@ -4246,16 +4245,11 @@ IntrusivePtr<Val> CallExpr::Eval(Frame* f) const
if ( f )
f->SetCall(this);
ret = func->Call(v, f);
ret = func->Call(*v, f);
if ( f )
f->SetCall(current_call);
// Don't Unref() the arguments, as Func::Call already did that.
delete v;
}
else
delete_vals(v);
return ret;
}
@ -4448,10 +4442,8 @@ IntrusivePtr<Val> EventExpr::Eval(Frame* f) const
if ( IsError() )
return nullptr;
val_list* v = eval_list(f, args.get());
mgr.QueueEvent(handler, std::move(*v));
delete v;
auto v = eval_list(f, args.get());
mgr.QueueUncheckedEvent(handler, std::move(*v));
return nullptr;
}
@ -5176,36 +5168,23 @@ int check_and_promote_exprs_to_type(ListExpr* const elements, BroType* type)
return 1;
}
val_list* eval_list(Frame* f, const ListExpr* l)
std::optional<std::vector<IntrusivePtr<Val>>> eval_list(Frame* f, const ListExpr* l)
{
const expr_list& e = l->Exprs();
val_list* v = new val_list(e.length());
bool success = true;
auto rval = std::make_optional<std::vector<IntrusivePtr<Val>>>();
rval->reserve(e.length());
for ( const auto& expr : e )
{
auto ev = expr->Eval(f);
if ( ! ev )
{
success = false;
break;
return {};
rval->emplace_back(std::move(ev));
}
v->push_back(ev.release());
}
if ( ! success )
{
for ( const auto& val : *v )
Unref(val);
delete v;
return nullptr;
}
else
return v;
return rval;
}
bool expr_greater(const Expr* e1, const Expr* e2)

View file

@ -9,10 +9,13 @@
#include "EventHandler.h"
#include "TraverseTypes.h"
#include "Val.h"
#include "ZeekArgs.h"
#include <memory>
#include <string>
#include <vector>
#include <utility>
#include <optional>
using std::string;
@ -737,15 +740,15 @@ protected:
class ScheduleTimer : public Timer {
public:
ScheduleTimer(EventHandlerPtr event, val_list* args, double t,
TimerMgr* tmgr);
ScheduleTimer(EventHandlerPtr event, zeek::Args args,
double t, TimerMgr* tmgr);
~ScheduleTimer() override;
void Dispatch(double t, int is_expire) override;
protected:
EventHandlerPtr event;
val_list args;
zeek::Args args;
TimerMgr* tmgr;
};
@ -936,9 +939,9 @@ extern int check_and_promote_exprs(ListExpr* elements, TypeList* types);
extern int check_and_promote_args(ListExpr* args, RecordType* types);
extern int check_and_promote_exprs_to_type(ListExpr* elements, BroType* type);
// Returns a ListExpr simplified down to a list a values, or a nil
// pointer if they couldn't all be reduced.
val_list* eval_list(Frame* f, const ListExpr* l);
// Returns a ListExpr simplified down to a list a values, or nil
// if they couldn't all be reduced.
std::optional<std::vector<IntrusivePtr<Val>>> eval_list(Frame* f, const ListExpr* l);
// Returns true if e1 is "greater" than e2 - here "greater" is just
// a heuristic, used with commutative operators to put them into

View file

@ -325,7 +325,7 @@ void BroFile::RaiseOpenEvent()
return;
Ref(this);
Event* event = new ::Event(::file_opened, {new Val(this)});
Event* event = new ::Event(::file_opened, {make_intrusive<Val>(this)});
mgr.Dispatch(event, true);
}

View file

@ -14,7 +14,7 @@
vector<Frame*> g_frame_stack;
Frame::Frame(int arg_size, const BroFunc* func, const val_list* fn_args)
Frame::Frame(int arg_size, const BroFunc* func, const zeek::Args* fn_args)
{
size = arg_size;
frame = new Val*[size];

View file

@ -5,6 +5,7 @@
#include "BroList.h" // for typedef val_list
#include "Obj.h"
#include "IntrusivePtr.h"
#include "ZeekArgs.h"
#include <unordered_map>
#include <string>
@ -28,7 +29,7 @@ public:
* @param func the function that is creating this frame
* @param fn_args the arguments being passed to that function.
*/
Frame(int size, const BroFunc* func, const val_list *fn_args);
Frame(int size, const BroFunc* func, const zeek::Args* fn_args);
/**
* Deletes the frame. Unrefs its trigger, the values that it
@ -100,7 +101,7 @@ public:
* @return the arguments passed to the function that this frame
* is associated with.
*/
const val_list* GetFuncArgs() const { return func_args; }
const zeek::Args* GetFuncArgs() const { return func_args; }
/**
* Change the function that the frame is associated with.
@ -283,7 +284,7 @@ private:
/** The function this frame is associated with. */
const BroFunc* function;
/** The arguments to the function that this Frame is associated with. */
const val_list* func_args;
const zeek::Args* func_args;
/** The next statement to be evaluted in the context of this frame. */
Stmt* next_stmt;

View file

@ -79,9 +79,7 @@ std::string render_call_stack()
auto name = ci.func->Name();
std::string arg_desc;
if ( ci.args )
{
for ( const auto& arg : *ci.args )
for ( const auto& arg : ci.args )
{
ODesc d;
d.SetShort();
@ -92,7 +90,6 @@ std::string render_call_stack()
arg_desc += d.Description();
}
}
rval += fmt("#%d %s(%s)", lvl, name, arg_desc.data());
@ -143,7 +140,7 @@ IntrusivePtr<Func> Func::DoClone()
return {NewRef{}, this};
}
void Func::DescribeDebug(ODesc* d, const val_list* args) const
void Func::DescribeDebug(ODesc* d, const zeek::Args* args) const
{
d->Add(Name());
@ -153,10 +150,10 @@ void Func::DescribeDebug(ODesc* d, const val_list* args) const
{
d->Add("(");
for ( int i = 0; i < args->length(); ++i )
for ( auto i = 0u; i < args->size(); ++i )
{
// Handle varargs case (more args than formals).
if ( i >= func_args->NumFields() )
if ( i >= static_cast<size_t>(func_args->NumFields()) )
{
d->Add("vararg");
d->Add(i - func_args->NumFields());
@ -167,7 +164,7 @@ void Func::DescribeDebug(ODesc* d, const val_list* args) const
d->Add(" = '");
(*args)[i]->Describe(d);
if ( i < args->length() - 1 )
if ( i < args->size() - 1 )
d->Add("', ");
else
d->Add("'");
@ -217,7 +214,7 @@ void Func::CopyStateInto(Func* other) const
other->unique_id = unique_id;
}
std::pair<bool, Val*> Func::HandlePluginResult(std::pair<bool, Val*> plugin_result, val_list* args, function_flavor flavor) const
std::pair<bool, Val*> Func::HandlePluginResult(std::pair<bool, Val*> plugin_result, function_flavor flavor) const
{
// Helper function factoring out this code from BroFunc:Call() for
// better readability.
@ -265,9 +262,6 @@ std::pair<bool, Val*> Func::HandlePluginResult(std::pair<bool, Val*> plugin_resu
}
}
for ( const auto& arg : *args )
Unref(arg);
return plugin_result;
}
@ -300,7 +294,12 @@ int BroFunc::IsPure() const
[](const Body& b) { return b.stmts->IsPure(); });
}
IntrusivePtr<Val> BroFunc::Call(val_list* args, Frame* parent) const
IntrusivePtr<Val> Func::Call(val_list* args, Frame* parent) const
{
return Call(zeek::val_list_to_args(args), parent);
}
IntrusivePtr<Val> BroFunc::Call(const zeek::Args& args, Frame* parent) const
{
#ifdef PROFILE_BRO_FUNCTIONS
DEBUG_MSG("Function: %s\n", Name());
@ -312,7 +311,7 @@ IntrusivePtr<Val> BroFunc::Call(val_list* args, Frame* parent) const
std::pair<bool, Val*> plugin_result = PLUGIN_HOOK_WITH_RESULT(HOOK_CALL_FUNCTION, HookCallFunction(this, parent, args), empty_hook_result);
plugin_result = HandlePluginResult(plugin_result, args, Flavor());
plugin_result = HandlePluginResult(plugin_result, Flavor());
if( plugin_result.first )
return {AdoptRef{}, plugin_result.second};
@ -321,13 +320,10 @@ IntrusivePtr<Val> BroFunc::Call(val_list* args, Frame* parent) const
{
// Can only happen for events and hooks.
assert(Flavor() == FUNC_FLAVOR_EVENT || Flavor() == FUNC_FLAVOR_HOOK);
for ( const auto& arg : *args )
Unref(arg);
return Flavor() == FUNC_FLAVOR_HOOK ? IntrusivePtr{AdoptRef{}, val_mgr->GetTrue()} : nullptr;
}
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);
@ -346,7 +342,7 @@ IntrusivePtr<Val> BroFunc::Call(val_list* args, Frame* parent) const
if ( g_trace_state.DoTrace() )
{
ODesc d;
DescribeDebug(&d, args);
DescribeDebug(&d, &args);
g_trace_state.LogTrace("%s called: %s\n",
FType()->FlavorString().c_str(), d.Description());
@ -362,19 +358,16 @@ IntrusivePtr<Val> BroFunc::Call(val_list* args, Frame* parent) const
body.stmts->GetLocationInfo());
// Fill in the rest of the frame with the function's arguments.
loop_over_list(*args, j)
for ( auto j = 0u; j < args.size(); ++j )
{
Val* arg = (*args)[j];
Val* arg = args[j].get();
if ( f->NthElement(j) != arg )
{
// Either not yet set, or somebody reassigned the frame slot.
Ref(arg);
f->SetElement(j, arg);
}
f->SetElement(j, arg->Ref());
}
f->Reset(args->length());
f->Reset(args.size());
try
{
@ -421,11 +414,6 @@ IntrusivePtr<Val> BroFunc::Call(val_list* args, Frame* parent) const
call_stack.pop_back();
// We have an extra Ref for each argument (so that they don't get
// deleted between bodies), release that.
for ( const auto& arg : *args )
Unref(arg);
if ( Flavor() == FUNC_FLAVOR_HOOK )
{
if ( ! result )
@ -612,7 +600,7 @@ int BuiltinFunc::IsPure() const
return is_pure;
}
IntrusivePtr<Val> BuiltinFunc::Call(val_list* args, Frame* parent) const
IntrusivePtr<Val> BuiltinFunc::Call(const zeek::Args& args, Frame* parent) const
{
#ifdef PROFILE_BRO_FUNCTIONS
DEBUG_MSG("Function: %s\n", Name());
@ -624,7 +612,7 @@ IntrusivePtr<Val> BuiltinFunc::Call(val_list* args, Frame* parent) const
std::pair<bool, Val*> plugin_result = PLUGIN_HOOK_WITH_RESULT(HOOK_CALL_FUNCTION, HookCallFunction(this, parent, args), empty_hook_result);
plugin_result = HandlePluginResult(plugin_result, args, FUNC_FLAVOR_FUNCTION);
plugin_result = HandlePluginResult(plugin_result, FUNC_FLAVOR_FUNCTION);
if ( plugin_result.first )
return {AdoptRef{}, plugin_result.second};
@ -632,20 +620,16 @@ IntrusivePtr<Val> BuiltinFunc::Call(val_list* args, Frame* parent) const
if ( g_trace_state.DoTrace() )
{
ODesc d;
DescribeDebug(&d, args);
DescribeDebug(&d, &args);
g_trace_state.LogTrace("\tBuiltin Function called: %s\n", d.Description());
}
const CallExpr* call_expr = parent ? parent->GetCall() : nullptr;
call_stack.emplace_back(CallInfo{call_expr, this, args});
IntrusivePtr<Val> result{AdoptRef{}, func(parent, args)};
IntrusivePtr<Val> result{AdoptRef{}, func(parent, &args)};
call_stack.pop_back();
for ( const auto& arg : *args )
Unref(arg);
// Don't Unref() args, that's the caller's responsibility.
if ( result && g_trace_state.DoTrace() )
{
ODesc d;
@ -663,6 +647,16 @@ void BuiltinFunc::Describe(ODesc* d) const
d->AddCount(is_pure);
}
void builtin_error(const char* msg)
{
builtin_error(msg, IntrusivePtr<Val>{});
}
void builtin_error(const char* msg, IntrusivePtr<Val> arg)
{
builtin_error(msg, arg.get());
}
void builtin_error(const char* msg, BroObj* arg)
{
auto emit = [=](const CallExpr* ce)

View file

@ -7,6 +7,7 @@
#include "IntrusivePtr.h"
#include "Type.h" /* for function_flavor */
#include "TraverseTypes.h"
#include "ZeekArgs.h"
#include <utility>
#include <memory>
@ -30,7 +31,6 @@ class Scope;
class Func : public BroObj {
public:
enum Kind { BRO_FUNC, BUILTIN_FUNC };
explicit Func(Kind arg_kind);
@ -50,7 +50,9 @@ public:
const vector<Body>& GetBodies() const { return bodies; }
bool HasBodies() const { return bodies.size(); }
virtual IntrusivePtr<Val> Call(val_list* args, Frame* parent = 0) const = 0;
// TODO: deprecate
virtual IntrusivePtr<Val> Call(val_list* args, Frame* parent = nullptr) const;
virtual IntrusivePtr<Val> Call(const zeek::Args& args, Frame* parent = nullptr) const = 0;
// Add a new event handler to an existing function (event).
virtual void AddBody(IntrusivePtr<Stmt> new_body, id_list* new_inits,
@ -67,7 +69,7 @@ public:
void SetName(const char* arg_name) { name = arg_name; }
void Describe(ODesc* d) const override = 0;
virtual void DescribeDebug(ODesc* d, const val_list* args) const;
virtual void DescribeDebug(ODesc* d, const zeek::Args* args) const;
virtual IntrusivePtr<Func> DoClone();
@ -84,7 +86,7 @@ protected:
void CopyStateInto(Func* other) const;
// Helper function for handling result of plugin hook.
std::pair<bool, Val*> HandlePluginResult(std::pair<bool, Val*> plugin_result, val_list* args, function_flavor flavor) const;
std::pair<bool, Val*> HandlePluginResult(std::pair<bool, Val*> plugin_result, function_flavor flavor) const;
vector<Body> bodies;
IntrusivePtr<Scope> scope;
@ -102,7 +104,7 @@ public:
~BroFunc() override;
int IsPure() const override;
IntrusivePtr<Val> Call(val_list* args, Frame* parent) const override;
IntrusivePtr<Val> Call(const zeek::Args& args, Frame* parent) const override;
/**
* Adds adds a closure to the function. Closures are cloned and
@ -169,7 +171,7 @@ private:
bool weak_closure_ref = false;
};
typedef Val* (*built_in_func)(Frame* frame, val_list* args);
using built_in_func = Val* (*)(Frame* frame, const zeek::Args* args);
class BuiltinFunc : public Func {
public:
@ -177,7 +179,7 @@ public:
~BuiltinFunc() override;
int IsPure() const override;
IntrusivePtr<Val> Call(val_list* args, Frame* parent) const override;
IntrusivePtr<Val> Call(const zeek::Args& args, Frame* parent) const override;
built_in_func TheFunc() const { return func; }
void Describe(ODesc* d) const override;
@ -190,7 +192,9 @@ protected:
};
extern void builtin_error(const char* msg, BroObj* arg = 0);
extern void builtin_error(const char* msg);
extern void builtin_error(const char* msg, IntrusivePtr<Val>);
extern void builtin_error(const char* msg, BroObj* arg);
extern void init_builtin_funcs();
extern void init_builtin_funcs_subdirs();
@ -199,7 +203,7 @@ extern bool check_built_in_call(BuiltinFunc* f, CallExpr* call);
struct CallInfo {
const CallExpr* call;
const Func* func;
const val_list* args;
const zeek::Args& args;
};
// Struct that collects all the specifics defining a Func. Used for BroFuncs

View file

@ -221,26 +221,7 @@ MD5Val::~MD5Val()
EVP_MD_CTX_free(ctx);
}
IntrusivePtr<Val> MD5Val::DoClone(CloneState* state)
{
auto out = make_intrusive<MD5Val>();
if ( IsValid() )
{
if ( ! out->Init() )
return nullptr;
EVP_MD_CTX_copy_ex(out->ctx, ctx);
}
return state->NewClone(this, std::move(out));
}
void MD5Val::digest(val_list& vlist, u_char result[MD5_DIGEST_LENGTH])
{
EVP_MD_CTX* h = hash_init(Hash_MD5);
for ( const auto& v : vlist )
void HashVal::digest_one(EVP_MD_CTX* h, const Val* v)
{
if ( v->Type()->Tag() == TYPE_STRING )
{
@ -255,18 +236,24 @@ void MD5Val::digest(val_list& vlist, u_char result[MD5_DIGEST_LENGTH])
}
}
hash_final(h, result);
void HashVal::digest_one(EVP_MD_CTX* h, const IntrusivePtr<Val>& v)
{
digest_one(h, v.get());
}
void MD5Val::hmac(val_list& vlist,
u_char key[MD5_DIGEST_LENGTH],
u_char result[MD5_DIGEST_LENGTH])
IntrusivePtr<Val> MD5Val::DoClone(CloneState* state)
{
digest(vlist, result);
for ( int i = 0; i < MD5_DIGEST_LENGTH; ++i )
result[i] ^= key[i];
auto out = make_intrusive<MD5Val>();
internal_md5(result, MD5_DIGEST_LENGTH, result);
if ( IsValid() )
{
if ( ! out->Init() )
return nullptr;
EVP_MD_CTX_copy_ex(out->ctx, ctx);
}
return state->NewClone(this, std::move(out));
}
bool MD5Val::DoInit()
@ -389,28 +376,6 @@ IntrusivePtr<Val> SHA1Val::DoClone(CloneState* state)
return state->NewClone(this, std::move(out));
}
void SHA1Val::digest(val_list& vlist, u_char result[SHA_DIGEST_LENGTH])
{
EVP_MD_CTX* h = hash_init(Hash_SHA1);
for ( const auto& v : vlist )
{
if ( v->Type()->Tag() == TYPE_STRING )
{
const BroString* str = v->AsString();
hash_update(h, str->Bytes(), str->Len());
}
else
{
ODesc d(DESC_BINARY);
v->Describe(&d);
hash_update(h, (const u_char *) d.Bytes(), d.Len());
}
}
hash_final(h, result);
}
bool SHA1Val::DoInit()
{
assert(! IsValid());
@ -535,28 +500,6 @@ IntrusivePtr<Val> SHA256Val::DoClone(CloneState* state)
return state->NewClone(this, std::move(out));
}
void SHA256Val::digest(val_list& vlist, u_char result[SHA256_DIGEST_LENGTH])
{
EVP_MD_CTX* h = hash_init(Hash_SHA256);
for ( const auto& v : vlist )
{
if ( v->Type()->Tag() == TYPE_STRING )
{
const BroString* str = v->AsString();
hash_update(h, str->Bytes(), str->Len());
}
else
{
ODesc d(DESC_BINARY);
v->Describe(&d);
hash_update(h, (const u_char *) d.Bytes(), d.Len());
}
}
hash_final(h, result);
}
bool SHA256Val::DoInit()
{
assert( ! IsValid() );

View file

@ -162,12 +162,26 @@ namespace probabilistic {
class HashVal : public OpaqueVal {
public:
template <class T>
static void digest_all(HashAlgorithm alg, const T& vlist, u_char* result)
{
auto h = hash_init(alg);
for ( const auto& v : vlist )
digest_one(h, v);
hash_final(h, result);
}
bool IsValid() const;
bool Init();
bool Feed(const void* data, size_t size);
IntrusivePtr<StringVal> Get();
protected:
static void digest_one(EVP_MD_CTX* h, const Val* v);
static void digest_one(EVP_MD_CTX* h, const IntrusivePtr<Val>& v);
HashVal() { valid = false; }
explicit HashVal(OpaqueType* t);
@ -182,11 +196,22 @@ private:
class MD5Val : public HashVal {
public:
static void digest(val_list& vlist, u_char result[MD5_DIGEST_LENGTH]);
template <class T>
static void digest(const T& vlist, u_char result[MD5_DIGEST_LENGTH])
{ digest_all(Hash_MD5, vlist, result); }
static void hmac(val_list& vlist,
template <class T>
static void hmac(const T& vlist,
u_char key[MD5_DIGEST_LENGTH],
u_char result[MD5_DIGEST_LENGTH]);
u_char result[MD5_DIGEST_LENGTH])
{
digest(vlist, result);
for ( int i = 0; i < MD5_DIGEST_LENGTH; ++i )
result[i] ^= key[i];
internal_md5(result, MD5_DIGEST_LENGTH, result);
}
MD5Val();
~MD5Val();
@ -207,7 +232,9 @@ private:
class SHA1Val : public HashVal {
public:
static void digest(val_list& vlist, u_char result[SHA_DIGEST_LENGTH]);
template <class T>
static void digest(const T& vlist, u_char result[SHA_DIGEST_LENGTH])
{ digest_all(Hash_SHA1, vlist, result); }
SHA1Val();
~SHA1Val();
@ -228,7 +255,9 @@ private:
class SHA256Val : public HashVal {
public:
static void digest(val_list& vlist, u_char result[SHA256_DIGEST_LENGTH]);
template <class T>
static void digest(const T& vlist, u_char result[SHA256_DIGEST_LENGTH])
{ digest_all(Hash_SHA256, vlist, result); }
SHA256Val();
~SHA256Val();

View file

@ -314,8 +314,8 @@ void ProfileLogger::Log()
{
Ref(file);
mgr.Dispatch(new Event(profiling_update, {
new Val(file),
val_mgr->GetBool(expensive),
make_intrusive<Val>(file),
{AdoptRef{}, val_mgr->GetBool(expensive)},
}));
}
}

View file

@ -151,14 +151,11 @@ IntrusivePtr<Val> ExprListStmt::Exec(Frame* f, stmt_flow_type& flow) const
last_access = network_time;
flow = FLOW_NEXT;
val_list* vals = eval_list(f, l.get());
auto vals = eval_list(f, l.get());
if ( vals )
{
auto result = DoExec(vals, flow);
delete_vals(vals);
return result;
}
else
return DoExec(std::move(*vals), flow);
return nullptr;
}
@ -169,11 +166,6 @@ void ExprListStmt::Describe(ODesc* d) const
DescribeDone(d);
}
void ExprListStmt::PrintVals(ODesc* d, val_list* vals, int offset) const
{
describe_vals(vals, d, offset);
}
TraversalCode ExprListStmt::Traverse(TraversalCallback* cb) const
{
TraversalCode tc = cb->PreStmt(this);
@ -206,13 +198,13 @@ static IntrusivePtr<EnumVal> lookup_enum_val(const char* module_name, const char
return et->GetVal(index);
}
static void print_log(val_list* vals)
static void print_log(const std::vector<IntrusivePtr<Val>>& vals)
{
auto plval = lookup_enum_val("Log", "PRINTLOG");
auto record = make_intrusive<RecordVal>(internal_type("Log::PrintLogInfo")->AsRecordType());
auto vec = make_intrusive<VectorVal>(internal_type("string_vec")->AsVectorType());
for ( const auto& val : *vals )
for ( const auto& val : vals )
{
ODesc d(DESC_READABLE);
val->Describe(&d);
@ -224,7 +216,8 @@ static void print_log(val_list* vals)
log_mgr->Write(plval.get(), record.get());
}
IntrusivePtr<Val> PrintStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */) const
IntrusivePtr<Val> PrintStmt::DoExec(std::vector<IntrusivePtr<Val>> vals,
stmt_flow_type& /* flow */) const
{
RegisterAccess();
@ -234,9 +227,9 @@ IntrusivePtr<Val> PrintStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */)
BroFile* f = print_stdout;
int offset = 0;
if ( vals->length() > 0 && (*vals)[0]->Type()->Tag() == TYPE_FILE )
if ( vals.size() > 0 && (vals)[0]->Type()->Tag() == TYPE_FILE )
{
f = (*vals)[0]->AsFile();
f = (vals)[0]->AsFile();
if ( ! f->IsOpen() )
return nullptr;
@ -277,7 +270,7 @@ IntrusivePtr<Val> PrintStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */)
d.SetFlush(0);
d.SetStyle(style);
PrintVals(&d, vals, offset);
describe_vals(vals, &d, offset);
f->Write(d.Description(), d.Len());
}
else
@ -286,7 +279,7 @@ IntrusivePtr<Val> PrintStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */)
d.SetFlush(0);
d.SetStyle(style);
PrintVals(&d, vals, offset);
describe_vals(vals, &d, offset);
f->Write("\n", 1);
}
@ -966,13 +959,10 @@ EventStmt::EventStmt(IntrusivePtr<EventExpr> arg_e)
IntrusivePtr<Val> EventStmt::Exec(Frame* f, stmt_flow_type& flow) const
{
RegisterAccess();
val_list* args = eval_list(f, event_expr->Args());
auto args = eval_list(f, event_expr->Args());
if ( args )
{
mgr.QueueEvent(event_expr->Handler(), std::move(*args));
delete args;
}
mgr.QueueUncheckedEvent(event_expr->Handler(), std::move(*args));
flow = FLOW_NEXT;
return nullptr;

View file

@ -95,10 +95,10 @@ protected:
~ExprListStmt() override;
IntrusivePtr<Val> Exec(Frame* f, stmt_flow_type& flow) const override;
virtual IntrusivePtr<Val> DoExec(val_list* vals, stmt_flow_type& flow) const = 0;
virtual IntrusivePtr<Val> DoExec(std::vector<IntrusivePtr<Val>> vals,
stmt_flow_type& flow) const = 0;
void Describe(ODesc* d) const override;
void PrintVals(ODesc* d, val_list* vals, int offset) const;
IntrusivePtr<ListExpr> l;
};
@ -109,7 +109,8 @@ public:
explicit PrintStmt(L&& l) : ExprListStmt(STMT_PRINT, std::forward<L>(l)) { }
protected:
IntrusivePtr<Val> DoExec(val_list* vals, stmt_flow_type& flow) const override;
IntrusivePtr<Val> DoExec(std::vector<IntrusivePtr<Val>> vals,
stmt_flow_type& flow) const override;
};
class ExprStmt : public Stmt {

View file

@ -3292,6 +3292,24 @@ void describe_vals(const val_list* vals, ODesc* d, int offset)
}
}
void describe_vals(const std::vector<IntrusivePtr<Val>>& vals,
ODesc* d, size_t offset)
{
if ( ! d->IsReadable() )
{
d->Add(vals.size());
d->SP();
}
for ( auto i = offset; i < vals.size(); ++i )
{
if ( i > offset && d->IsReadable() && d->Style() != RAW_STYLE )
d->Add(", ");
vals[i]->Describe(d);
}
}
void delete_vals(val_list* vals)
{
if ( vals )

View file

@ -1042,6 +1042,8 @@ extern int same_val(const Val* v1, const Val* v2);
extern int same_atomic_val(const Val* v1, const Val* v2);
extern bool is_atomic_val(const Val* v);
extern void describe_vals(const val_list* vals, ODesc* d, int offset=0);
extern void describe_vals(const std::vector<IntrusivePtr<Val>>& vals,
ODesc* d, size_t offset = 0);
extern void delete_vals(val_list* vals);
// True if the given Val* has a vector type.

15
src/ZeekArgs.cc Normal file
View file

@ -0,0 +1,15 @@
#include "ZeekArgs.h"
#include "IntrusivePtr.h"
#include "Val.h"
zeek::Args zeek::val_list_to_args(const val_list* vl)
{
zeek::Args rval;
rval.reserve(vl->length());
for ( auto& v : *vl )
rval.emplace_back(AdoptRef{}, v);
return rval;
}

27
src/ZeekArgs.h Normal file
View file

@ -0,0 +1,27 @@
// See the file "COPYING" in the main distribution directory for copyright.
#pragma once
#include "BroList.h"
#include <vector>
class Val;
template <class T> class IntrusivePtr;
namespace zeek {
using Args = std::vector<IntrusivePtr<Val>>;
/**
* Converts a legacy-style argument list for use in modern Zeek function
* calling or event queueing APIs.
* @param vl the argument list to convert, the returned value takes ownership
* of a reference to each element in the list, but not ownership of the list
* itself.
* @return the converted argument list
*
*/
Args val_list_to_args(const val_list* vl);
} // namespace zeek

View file

@ -83,7 +83,13 @@ type Broker::Event: record;
function Broker::make_event%(...%): Broker::Event
%{
bro_broker::Manager::ScriptScopeGuard ssg;
auto rval = broker_mgr->MakeEvent(@ARGS@, frame);
const auto& bif_args = @ARGS@;
val_list args(bif_args->size());
for ( auto i = 0u; i < bif_args->size(); ++i )
args.push_back((*bif_args)[i].get());
auto rval = broker_mgr->MakeEvent(&args, frame);
return rval;
%}
@ -98,11 +104,11 @@ function Broker::make_event%(...%): Broker::Event
## Returns: true if the message is sent.
function Broker::publish%(topic: string, ...%): bool
%{
val_list* bif_args = @ARGS@;
val_list args(bif_args->length() - 1);
const auto& bif_args = @ARGS@;
val_list args(bif_args->size() - 1);
for ( auto i = 1; i < bif_args->length(); ++i )
args.push_back((*bif_args)[i]);
for ( auto i = 1u; i < bif_args->size(); ++i )
args.push_back((*bif_args)[i].get());
auto rval = publish_event_args(args, topic->AsString(), frame);
return val_mgr->GetBool(rval);
@ -188,11 +194,11 @@ function Cluster::publish_rr%(pool: Pool, key: string, ...%): bool
if ( ! topic->AsString()->Len() )
return val_mgr->GetFalse();
val_list* bif_args = @ARGS@;
val_list args(bif_args->length() - 2);
const auto& bif_args = @ARGS@;
val_list args(bif_args->size() - 2);
for ( auto i = 2; i < bif_args->length(); ++i )
args.push_back((*bif_args)[i]);
for ( auto i = 2u; i < bif_args->size(); ++i )
args.push_back((*bif_args)[i].get());
auto rval = publish_event_args(args, topic->AsString(), frame);
return val_mgr->GetBool(rval);
@ -225,11 +231,11 @@ function Cluster::publish_hrw%(pool: Pool, key: any, ...%): bool
if ( ! topic->AsString()->Len() )
return val_mgr->GetFalse();
val_list* bif_args = @ARGS@;
val_list args(bif_args->length() - 2);
const auto& bif_args = @ARGS@;
val_list args(bif_args->size() - 2);
for ( auto i = 2; i < bif_args->length(); ++i )
args.push_back((*bif_args)[i]);
for ( auto i = 2u; i < bif_args->size(); ++i )
args.push_back((*bif_args)[i].get());
auto rval = publish_event_args(args, topic->AsString(), frame);
return val_mgr->GetBool(rval);

View file

@ -218,7 +218,7 @@ void done_with_network()
mgr.Drain();
// Don't propagate this event to remote clients.
mgr.Dispatch(new Event(net_done,
{new Val(timer_mgr->Time(), TYPE_TIME)}),
{make_intrusive<Val>(timer_mgr->Time(), TYPE_TIME)}),
true);
}

View file

@ -1,5 +1,6 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include <optional>
#include <sstream>
#include <fstream>
#include <dirent.h>
@ -619,15 +620,21 @@ int Manager::HookLoadFile(const Plugin::LoadType type, const string& file, const
return rc;
}
std::pair<bool, Val*> Manager::HookCallFunction(const Func* func, Frame* parent, val_list* vargs) const
std::pair<bool, Val*> Manager::HookCallFunction(const Func* func, Frame* parent, const zeek::Args& vecargs) const
{
HookArgumentList args;
std::optional<val_list> vargs;
if ( HavePluginForHook(META_HOOK_PRE) )
{
vargs = val_list(vecargs.size());
for ( const auto& v : vecargs )
vargs->push_back(v.get());
args.push_back(HookArgument(func));
args.push_back(HookArgument(parent));
args.push_back(HookArgument(vargs));
args.push_back(HookArgument(&vargs.value()));
MetaHookPre(HOOK_CALL_FUNCTION, args);
}
@ -637,11 +644,19 @@ std::pair<bool, Val*> Manager::HookCallFunction(const Func* func, Frame* parent,
if ( l )
{
if ( ! vargs )
{
vargs = val_list(vecargs.size());
for ( const auto& v : vecargs )
vargs->push_back(v.get());
}
for ( hook_list::iterator i = l->begin(); i != l->end(); ++i )
{
Plugin* p = (*i).second;
v = p->HookCallFunction(func, parent, vargs);
v = p->HookCallFunction(func, parent, &vargs.value());
if ( v.first )
break;

View file

@ -6,11 +6,11 @@
#include <map>
#include <string_view>
#include "Plugin.h"
#include "Component.h"
#include "../Reporter.h"
#include "../ZeekArgs.h"
namespace plugin {
@ -253,7 +253,7 @@ public:
* functions and events, it may be any Val and must be ignored). If no
* plugin handled the call, the method returns null.
*/
std::pair<bool, Val*> HookCallFunction(const Func* func, Frame *parent, val_list* args) const;
std::pair<bool, Val*> HookCallFunction(const Func* func, Frame* parent, const zeek::Args& args) const;
/**
* Hook that filters the queuing of an event.

View file

@ -19,6 +19,7 @@ class ODesc;
class Frame;
class Func;
class Event;
template <class T> class IntrusivePtr;
namespace threading {
struct Field;

View file

@ -267,7 +267,7 @@ static void do_fmt(const char*& fmt, Val* v, ODesc* d)
++fmt;
}
static int next_fmt(const char*& fmt, val_list* args, ODesc* d, int& n)
static int next_fmt(const char*& fmt, const zeek::Args* args, ODesc* d, int& n)
{
const char* fp = fmt;
@ -290,10 +290,10 @@ static int next_fmt(const char*& fmt, val_list* args, ODesc* d, int& n)
return next_fmt(fmt, args, d, n);
}
if ( ++n >= args->length() )
if ( ++n >= static_cast<int>(args->size()) )
return 0;
do_fmt(fmt, (*args)[n], d);
do_fmt(fmt, (*args)[n].get(), d);
return *fmt != '\0';
}
@ -1413,12 +1413,12 @@ function sort%(v: any, ...%) : any
BroType* elt_type = v->Type()->YieldType();
Func* comp = 0;
if ( @ARG@.length() > 2 )
if ( @ARG@.size() > 2 )
builtin_error("sort() called with extraneous argument");
if ( @ARG@.length() == 2 )
if ( @ARG@.size() == 2 )
{
Val* comp_val = @ARG@[1];
Val* comp_val = @ARG@[1].get();
if ( ! IsFunc(comp_val->Type()->Tag()) )
{
builtin_error("second argument to sort() needs to be comparison function");
@ -1483,12 +1483,12 @@ function order%(v: any, ...%) : index_vec
BroType* elt_type = v->Type()->YieldType();
Func* comp = 0;
if ( @ARG@.length() > 2 )
if ( @ARG@.size() > 2 )
builtin_error("order() called with extraneous argument");
if ( @ARG@.length() == 2 )
if ( @ARG@.size() == 2 )
{
Val* comp_val = @ARG@[1];
Val* comp_val = @ARG@[1].get();
if ( ! IsFunc(comp_val->Type()->Tag()) )
{
builtin_error("second argument to order() needs to be comparison function");
@ -1595,7 +1595,7 @@ function cat_sep%(sep: string, def: string, ...%): string
int pre_size = 0;
loop_over_list(@ARG@, i)
for ( auto i = 0u; i < @ARG@.size(); ++i )
{
// Skip named parameters.
if ( i < 2 )
@ -1604,7 +1604,7 @@ function cat_sep%(sep: string, def: string, ...%): string
if ( i > 2 )
d.Add(sep->CheckString(), 0);
Val* v = @ARG@[i];
Val* v = @ARG@[i].get();
if ( v->Type()->Tag() == TYPE_STRING && ! v->AsString()->Len() )
v = def;
@ -1660,7 +1660,7 @@ function fmt%(...%): string
if ( @ARGC@ == 0 )
return val_mgr->GetEmptyString();
Val* fmt_v = @ARG@[0];
Val* fmt_v = @ARG@[0].get();
// Type of fmt_v will be string here, check_built_in_call() in Func.cc
// checks that.
@ -1674,13 +1674,13 @@ function fmt%(...%): string
while ( next_fmt(fmt, @ARGS@, &d, n) )
;
if ( n < @ARGC@ - 1 )
if ( n < static_cast<int>(@ARGC@) - 1 )
{
builtin_error("too many arguments for format", fmt_v);
return val_mgr->GetEmptyString();
}
else if ( n >= @ARGC@ )
else if ( n >= static_cast<int>(@ARGC@) )
{
builtin_error("too few arguments for format", fmt_v);
return val_mgr->GetEmptyString();
@ -1703,7 +1703,7 @@ function print_raw%(...%): bool
%{
ODesc d(DESC_READABLE);
d.SetStyle(RAW_STYLE);
describe_vals(&@ARG@, &d, 0);
describe_vals(@ARG@, &d, 0);
printf("%.*s", d.Len(), d.Description());
return val_mgr->GetBool(true);
%}