zeek/src/Val.h
Robin Sommer bd9c937236 Fixing DNS memory leaks.
Some of the changes only clean up at termination to make perftools
happt, but there were some "real" leaks as well.

This fixes all DNS leaks I could reproducem, including most likely
what's reported in #534. Closing #534.

I'm also adding a new btest subdir core/leaks with tests requiring
perftools support. These don't compare against base lines but abort
whenever perftools reports a leak (with stack information to track it
down). Right now, these are passing.
2011-10-09 17:00:57 -07:00

1037 lines
26 KiB
C++

// See the file "COPYING" in the main distribution directory for copyright.
#ifndef val_h
#define val_h
// BRO values.
#include <vector>
#include <list>
#include "net_util.h"
#include "Type.h"
#include "Dict.h"
#include "CompHash.h"
#include "BroString.h"
#include "Attr.h"
#include "Timer.h"
#include "ID.h"
#include "Scope.h"
#include "StateAccess.h"
class Val;
class Func;
class BroFile;
class RE_Matcher;
class PrefixTable;
class SerialInfo;
class PortVal;
class AddrVal;
class SubNetVal;
class IntervalVal;
class PatternVal;
class TableVal;
class RecordVal;
class ListVal;
class StringVal;
class EnumVal;
class MutableVal;
class StateAccess;
class VectorVal;
class TableEntryVal;
declare(PDict,TableEntryVal);
typedef union {
// Used for bool, int, enum.
bro_int_t int_val;
// Used for count, counter, port, subnet.
bro_uint_t uint_val;
// Used for addr, net
addr_type addr_val;
// Used for subnet
subnet_type subnet_val;
// Used for double, time, interval.
double double_val;
BroString* string_val;
Func* func_val;
BroFile* file_val;
RE_Matcher* re_val;
PDict(TableEntryVal)* table_val;
val_list* val_list_val;
vector<Val*>* vector_val;
} BroValUnion;
class Val : public BroObj {
public:
Val(bool b, TypeTag t)
{
val.int_val = b;
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
}
Val(int32 i, TypeTag t)
{
val.int_val = bro_int_t(i);
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
}
Val(uint32 u, TypeTag t)
{
val.uint_val = bro_uint_t(u);
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
}
Val(int64 i, TypeTag t)
{
val.int_val = i;
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
}
Val(uint64 u, TypeTag t)
{
val.uint_val = u;
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
}
Val(double d, TypeTag t)
{
val.double_val = d;
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
}
Val(Func* f);
// Note, will unref 'f' when it's done, closing it unless
// class has ref'd it.
Val(BroFile* f);
Val(BroType* t, bool type_type) // Extra arg to differentiate from protected version.
{
type = new TypeType(t->Ref());
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
}
Val()
{
val.int_val = 0;
type = base_type(TYPE_ERROR);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
}
virtual ~Val();
Val* Ref() { ::Ref(this); return this; }
virtual Val* Clone() const;
int IsZero() const;
int IsOne() const;
bro_int_t InternalInt() const;
bro_uint_t InternalUnsigned() const;
double InternalDouble() const;
bro_int_t CoerceToInt() const;
bro_uint_t CoerceToUnsigned() const;
double CoerceToDouble() const;
// Returns a new Val with the "size" of this Val. What constitutes
// size depends on the Val's type.
virtual Val* SizeVal() const;
// Bytes in total value object.
virtual unsigned int MemoryAllocation() const;
// Add this value to the given value (if appropriate).
// Returns true if succcessful. is_first_init is true only if
// this is the *first* initialization of the value, not
// if it's a subsequent += initialization.
virtual int AddTo(Val* v, int is_first_init) const;
// Remove this value from the given value (if appropriate).
virtual int RemoveFrom(Val* v) const;
BroType* Type() { return type; }
const BroType* Type() const { return type; }
#define CONST_ACCESSOR(tag, ctype, accessor, name) \
const ctype name() const \
{ \
CHECK_TAG(type->Tag(), tag, "Val::CONST_ACCESSOR", type_name) \
return val.accessor; \
}
// Needed for g++ 4.3's pickiness.
#define CONST_ACCESSOR2(tag, ctype, accessor, name) \
ctype name() const \
{ \
CHECK_TAG(type->Tag(), tag, "Val::CONST_ACCESSOR", type_name) \
return val.accessor; \
}
CONST_ACCESSOR2(TYPE_BOOL, bool, int_val, AsBool)
CONST_ACCESSOR2(TYPE_INT, bro_int_t, int_val, AsInt)
CONST_ACCESSOR2(TYPE_COUNT, bro_uint_t, uint_val, AsCount)
CONST_ACCESSOR2(TYPE_COUNTER, bro_uint_t, uint_val, AsCounter)
CONST_ACCESSOR2(TYPE_DOUBLE, double, double_val, AsDouble)
CONST_ACCESSOR2(TYPE_TIME, double, double_val, AsTime)
CONST_ACCESSOR2(TYPE_INTERVAL, double, double_val, AsInterval)
CONST_ACCESSOR2(TYPE_ENUM, int, int_val, AsEnum)
CONST_ACCESSOR(TYPE_STRING, BroString*, string_val, AsString)
CONST_ACCESSOR(TYPE_FUNC, Func*, func_val, AsFunc)
CONST_ACCESSOR(TYPE_TABLE, PDict(TableEntryVal)*, table_val, AsTable)
CONST_ACCESSOR(TYPE_RECORD, val_list*, val_list_val, AsRecord)
CONST_ACCESSOR(TYPE_FILE, BroFile*, file_val, AsFile)
CONST_ACCESSOR(TYPE_PATTERN, RE_Matcher*, re_val, AsPattern)
CONST_ACCESSOR(TYPE_VECTOR, vector<Val*>*, vector_val, AsVector)
const subnet_type* AsSubNet() const
{
CHECK_TAG(type->Tag(), TYPE_SUBNET, "Val::SubNet", type_name)
return &val.subnet_val;
}
BroType* AsType() const
{
CHECK_TAG(type->Tag(), TYPE_TYPE, "Val::Type", type_name)
return type;
}
// ... in network byte order
const addr_type AsAddr() const
{
if ( type->Tag() != TYPE_ADDR )
BadTag("Val::AsAddr", type_name(type->Tag()));
return val.addr_val;
}
#define ACCESSOR(tag, ctype, accessor, name) \
ctype name() \
{ \
CHECK_TAG(type->Tag(), tag, "Val::ACCESSOR", type_name) \
return val.accessor; \
}
// Accessors for mutable values are called AsNonConst* and
// are protected to avoid external state changes.
// ACCESSOR(TYPE_STRING, BroString*, string_val, AsString)
ACCESSOR(TYPE_FUNC, Func*, func_val, AsFunc)
ACCESSOR(TYPE_FILE, BroFile*, file_val, AsFile)
ACCESSOR(TYPE_PATTERN, RE_Matcher*, re_val, AsPattern)
ACCESSOR(TYPE_VECTOR, vector<Val*>*, vector_val, AsVector)
subnet_type* AsSubNet()
{
CHECK_TAG(type->Tag(), TYPE_SUBNET, "Val::SubNet", type_name)
return &val.subnet_val;
}
// Gives fast access to the bits of something that is one of
// bool, int, count, or counter.
bro_int_t ForceAsInt() const { return val.int_val; }
bro_uint_t ForceAsUInt() const { return val.uint_val; }
#define CONVERTER(tag, ctype, name) \
ctype name() \
{ \
CHECK_TAG(type->Tag(), tag, "Val::CONVERTER", type_name) \
return (ctype)(this); \
}
CONVERTER(TYPE_PATTERN, PatternVal*, AsPatternVal)
CONVERTER(TYPE_PORT, PortVal*, AsPortVal)
CONVERTER(TYPE_SUBNET, SubNetVal*, AsSubNetVal)
CONVERTER(TYPE_TABLE, TableVal*, AsTableVal)
CONVERTER(TYPE_RECORD, RecordVal*, AsRecordVal)
CONVERTER(TYPE_LIST, ListVal*, AsListVal)
CONVERTER(TYPE_STRING, StringVal*, AsStringVal)
CONVERTER(TYPE_VECTOR, VectorVal*, AsVectorVal)
CONVERTER(TYPE_ENUM, EnumVal*, AsEnumVal)
#define CONST_CONVERTER(tag, ctype, name) \
const ctype name() const \
{ \
CHECK_TAG(type->Tag(), tag, "Val::CONVERTER", type_name) \
return (const ctype)(this); \
}
CONST_CONVERTER(TYPE_PATTERN, PatternVal*, AsPatternVal)
CONST_CONVERTER(TYPE_PORT, PortVal*, AsPortVal)
CONST_CONVERTER(TYPE_SUBNET, SubNetVal*, AsSubNetVal)
CONST_CONVERTER(TYPE_TABLE, TableVal*, AsTableVal)
CONST_CONVERTER(TYPE_RECORD, RecordVal*, AsRecordVal)
CONST_CONVERTER(TYPE_LIST, ListVal*, AsListVal)
CONST_CONVERTER(TYPE_STRING, StringVal*, AsStringVal)
CONST_CONVERTER(TYPE_VECTOR, VectorVal*, AsVectorVal)
bool IsMutableVal() const
{
return IsMutable(type->Tag());
}
const MutableVal* AsMutableVal() const
{
if ( ! IsMutableVal() )
BadTag("Val::AsMutableVal", type_name(type->Tag()));
return (MutableVal*) this;
}
MutableVal* AsMutableVal()
{
if ( ! IsMutableVal() )
BadTag("Val::AsMutableVal", type_name(type->Tag()));
return (MutableVal*) this;
}
void Describe(ODesc* d) const;
virtual void DescribeReST(ODesc* d) const;
bool Serialize(SerialInfo* info) const;
static Val* Unserialize(UnserialInfo* info, TypeTag type = TYPE_ANY)
{ return Unserialize(info, type, 0); }
static Val* Unserialize(UnserialInfo* info, const BroType* exact_type)
{ return Unserialize(info, exact_type->Tag(), exact_type); }
DECLARE_SERIAL(Val);
#ifdef DEBUG
// For debugging, we keep a reference to the global ID to which a
// value has been bound *last*.
ID* GetID() const { return bound_id; }
void SetID(ID* id)
{
if ( bound_id )
::Unref(bound_id);
bound_id = id;
::Ref(bound_id);
}
#endif
protected:
Val(BroString* s, TypeTag t)
{
val.string_val = s;
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
}
virtual void ValDescribe(ODesc* d) const;
virtual void ValDescribeReST(ODesc* d) const;
Val(TypeTag t)
{
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
}
Val(BroType* t)
{
type = t->Ref();
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
}
ACCESSOR(TYPE_TABLE, PDict(TableEntryVal)*, table_val, AsNonConstTable)
ACCESSOR(TYPE_RECORD, val_list*, val_list_val, AsNonConstRecord)
// Just an internal helper.
static Val* Unserialize(UnserialInfo* info, TypeTag type,
const BroType* exact_type);
BroValUnion val;
BroType* type;
RecordVal* attribs;
#ifdef DEBUG
// For debugging, we keep the ID to which a Val is bound.
ID* bound_id;
#endif
};
class MutableVal : public Val {
public:
// Each MutableVal gets a globally unique ID that can be used to
// reference it no matter if it's directly bound to any user-visible
// ID. This ID is inserted into the global namespace.
ID* UniqueID() const { return id ? id : Bind(); }
// Returns true if we've already generated a unique ID.
bool HasUniqueID() const { return id; }
// Transfers the unique ID of the given value to this value. We keep our
// old ID as an alias.
void TransferUniqueID(MutableVal* mv);
// MutableVals can have properties (let's refrain from calling them
// attributes!). Most properties are recursive. If a derived object
// can contain MutableVals itself, the object has to override
// {Add,Remove}Properties(). RecursiveProp(state) masks out all non-
// recursive properties. If this is non-null, an overriden method must
// call itself with RecursiveProp(state) as argument for all contained
// values. (In any case, don't forget to call the parent's method.)
typedef char Properties;
static const int PERSISTENT = 0x01;
static const int SYNCHRONIZED = 0x02;
// Tracked by NotifierRegistry, not recursive.
static const int TRACKED = 0x04;
int RecursiveProps(int prop) const { return prop & ~TRACKED; }
Properties GetProperties() const { return props; }
virtual bool AddProperties(Properties state);
virtual bool RemoveProperties(Properties state);
// Whether StateAccess:LogAccess needs to be called.
bool LoggingAccess() const
{
#ifndef DEBUG
return props & (SYNCHRONIZED|PERSISTENT|TRACKED);
#else
return debug_logger.IsVerbose() ||
(props & (SYNCHRONIZED|PERSISTENT|TRACKED));
#endif
}
virtual uint64 LastModified() const { return last_modified; }
// Mark value as changed.
void Modified()
{
last_modified = IncreaseTimeCounter();
}
protected:
MutableVal(BroType* t) : Val(t)
{ props = 0; id = 0; last_modified = SerialObj::ALWAYS; }
MutableVal() { id = 0; last_modified = SerialObj::ALWAYS; }
~MutableVal();
friend class ID;
friend class Val;
void SetID(ID* arg_id) { Unref(id); id = arg_id; }
DECLARE_SERIAL(MutableVal);
private:
ID* Bind() const;
mutable ID* id;
list<ID*> aliases;
Properties props;
uint64 last_modified;
};
#define Microseconds 1e-6
#define Milliseconds 1e-3
#define Seconds 1.0
#define Minutes (60*Seconds)
#define Hours (60*Minutes)
#define Days (24*Hours)
class IntervalVal : public Val {
public:
IntervalVal(double quantity, double units);
protected:
IntervalVal() {}
void ValDescribe(ODesc* d) const;
DECLARE_SERIAL(IntervalVal);
};
// We have four different port name spaces: TCP, UDP, ICMP, and UNKNOWN.
// We distinguish between them based on the bits specified in the *_PORT_MASK
// entries specified below.
#define NUM_PORT_SPACES 4
#define PORT_SPACE_MASK 0x30000
#define TCP_PORT_MASK 0x10000
#define UDP_PORT_MASK 0x20000
#define ICMP_PORT_MASK 0x30000
typedef enum {
TRANSPORT_UNKNOWN, TRANSPORT_TCP, TRANSPORT_UDP, TRANSPORT_ICMP,
} TransportProto;
class PortVal : public Val {
public:
// Constructors - both take the port number in host order.
PortVal(uint32 p, TransportProto port_type);
PortVal(uint32 p); // used for already-massaged port value.
Val* SizeVal() const { return new Val(val.uint_val, TYPE_INT); }
// Returns the port number in host order (not including the mask).
uint32 Port() const;
// Tests for protocol types.
int IsTCP() const;
int IsUDP() const;
int IsICMP() const;
TransportProto PortType() const
{
if ( IsTCP() )
return TRANSPORT_TCP;
else if ( IsUDP() )
return TRANSPORT_UDP;
else if ( IsICMP() )
return TRANSPORT_ICMP;
else
return TRANSPORT_UNKNOWN;
}
protected:
friend class Val;
PortVal() {}
void ValDescribe(ODesc* d) const;
DECLARE_SERIAL(PortVal);
};
class AddrVal : public Val {
public:
AddrVal(const char* text);
~AddrVal();
Val* SizeVal() const;
// Constructor for address already in network order.
AddrVal(uint32 addr);
AddrVal(const uint32* addr);
unsigned int MemoryAllocation() const;
protected:
friend class Val;
AddrVal() {}
AddrVal(TypeTag t) : Val(t) { }
AddrVal(BroType* t) : Val(t) { }
void Init(uint32 addr);
void Init(const uint32* addr);
DECLARE_SERIAL(AddrVal);
};
class SubNetVal : public Val {
public:
SubNetVal(const char* text);
SubNetVal(const char* text, int width);
SubNetVal(uint32 addr, int width); // for address already massaged
SubNetVal(const uint32* addr, int width); // ditto
Val* SizeVal() const;
int Width() const { return val.subnet_val.width; }
addr_type Mask() const; // returns host byte order
bool Contains(const uint32 addr) const;
bool Contains(const uint32* addr) const;
unsigned int MemoryAllocation() const
{
return Val::MemoryAllocation() + padded_sizeof(*this) - padded_sizeof(Val);
}
protected:
friend class Val;
SubNetVal() {}
void Init(const char* text, int width);
void Init(uint32 addr, int width);
void Init(const uint32 *addr, int width);
void ValDescribe(ODesc* d) const;
DECLARE_SERIAL(SubNetVal);
};
class StringVal : public Val {
public:
StringVal(BroString* s);
StringVal(const char* s);
StringVal(int length, const char* s);
Val* SizeVal() const
{ return new Val(val.string_val->Len(), TYPE_COUNT); }
int Len() { return AsString()->Len(); }
const u_char* Bytes() { return AsString()->Bytes(); }
const char* CheckString() { return AsString()->CheckString(); }
// Note that one needs to de-allocate the return value of
// ExpandedString() to avoid a memory leak.
// char* ExpandedString(int format = BroString::EXPANDED_STRING)
// { return AsString()->ExpandedString(format); }
StringVal* ToUpper();
unsigned int MemoryAllocation() const;
protected:
friend class Val;
StringVal() {}
void ValDescribe(ODesc* d) const;
DECLARE_SERIAL(StringVal);
};
class PatternVal : public Val {
public:
PatternVal(RE_Matcher* re);
~PatternVal();
int AddTo(Val* v, int is_first_init) const;
void SetMatcher(RE_Matcher* re);
unsigned int MemoryAllocation() const;
protected:
friend class Val;
PatternVal() {}
void ValDescribe(ODesc* d) const;
DECLARE_SERIAL(PatternVal);
};
class ListVal : public Val {
public:
ListVal(TypeTag t);
~ListVal();
TypeTag BaseTag() const { return tag; }
Val* SizeVal() const { return new Val(vals.length(), TYPE_COUNT); }
int Length() const { return vals.length(); }
Val* Index(const int n) { return vals[n]; }
const Val* Index(const int n) const { return vals[n]; }
// Returns offset of where str includes one of the strings in this
// ListVal (which had better be a list of strings), nil if none.
//
// Assumes that all of the strings in the list are NUL-terminated
// and do not have any embedded NULs.
const char* IncludedInString(const char* str) const;
// Returns an RE_Matcher() that will match any string that
// includes embedded within it one of the patterns listed
// (as a string, e.g., "foo|bar") in this ListVal.
//
// Assumes that all of the strings in the list are NUL-terminated
// and do not have any embedded NULs.
//
// The return RE_Matcher has not yet been compiled.
RE_Matcher* BuildRE() const;
void Append(Val* v);
// Returns a Set representation of the list (which must be homogeneous).
TableVal* ConvertToSet() const;
const val_list* Vals() const { return &vals; }
val_list* Vals() { return &vals; }
void Describe(ODesc* d) const;
unsigned int MemoryAllocation() const;
protected:
friend class Val;
ListVal() {}
DECLARE_SERIAL(ListVal);
val_list vals;
TypeTag tag;
};
extern double bro_start_network_time;
class TableEntryVal {
public:
TableEntryVal(Val* v)
{
val = v;
last_access_time = network_time;
expire_access_time = last_read_update =
int(network_time - bro_start_network_time);
}
~TableEntryVal() { }
Val* Value() { return val; }
void Ref() { val->Ref(); }
void Unref() { ::Unref(val); }
// Returns/sets time of last expiration relevant access to this value.
double ExpireAccessTime() const
{ return bro_start_network_time + expire_access_time; }
void SetExpireAccess(double time)
{ expire_access_time = int(time - bro_start_network_time); }
// Returns/sets time of when we propagated the last OP_READ_IDX
// for this item.
double LastReadUpdate() const
{ return bro_start_network_time + last_read_update; }
void SetLastReadUpdate(double time)
{ last_read_update = int(time - bro_start_network_time); }
protected:
friend class TableVal;
Val* val;
double last_access_time;
// The next two entries store seconds since Bro's start. We use
// ints here to save a few bytes, as we do not need a high resolution
// for these anyway.
int expire_access_time;
int last_read_update;
};
class TableValTimer : public Timer {
public:
TableValTimer(TableVal* val, double t);
~TableValTimer();
virtual void Dispatch(double t, int is_expire);
TableVal* Table() { return table; }
protected:
TableVal* table;
};
class CompositeHash;
class TableVal : public MutableVal {
public:
TableVal(TableType* t, Attributes* attrs = 0);
~TableVal();
// Returns true if the assignment typechecked, false if not.
// Second version takes a HashKey and Unref()'s it when done.
// If we're a set, new_val has to be nil.
// If we aren't a set, index may be nil in the second version.
int Assign(Val* index, Val* new_val, Opcode op = OP_ASSIGN);
int Assign(Val* index, HashKey* k, Val* new_val, Opcode op = OP_ASSIGN);
Val* SizeVal() const { return new Val(Size(), TYPE_COUNT); }
// Add the entire contents of the table to the given value,
// which must also be a TableVal.
// Returns true if the addition typechecked, false if not.
// If is_first_init is true, then this is the *first* initialization
// (and so should be strictly adding new elements).
int AddTo(Val* v, int is_first_init) const;
// Same but allows suppression of state operations.
int AddTo(Val* v, int is_first_init, bool propagate_ops) const;
// Remove the entire contents.
void RemoveAll();
// Remove the entire contents of the table from the given value.
// which must also be a TableVal.
// Returns true if the addition typechecked, false if not.
int RemoveFrom(Val* v) const;
// Expands any lists in the index into multiple initializations.
// Returns true if the initializations typecheck, false if not.
int ExpandAndInit(Val* index, Val* new_val);
// Returns the element's value if it exists in the table,
// nil otherwise. Note, "index" is not const because we
// need to Ref/Unref it when calling the default function.
Val* Lookup(Val* index, bool use_default_val = true);
// Sets the timestamp for the given index to network time.
// Returns false if index does not exist.
bool UpdateTimestamp(Val* index);
// Returns the index corresponding to the given HashKey.
ListVal* RecoverIndex(const HashKey* k) const;
// Returns the element if it was in the table, false otherwise.
Val* Delete(const Val* index);
Val* Delete(const HashKey* k);
// Returns a ListVal representation of the table (which must be a set).
ListVal* ConvertToList(TypeTag t=TYPE_ANY) const;
ListVal* ConvertToPureList() const; // must be single index type
void SetAttrs(Attributes* attrs);
Attr* FindAttr(attr_tag t) const
{ return attrs ? attrs->FindAttr(t) : 0; }
Attributes* Attrs() { return attrs; }
// Returns the size of the table.
int Size() const { return AsTable()->Length(); }
int RecursiveSize() const;
void Describe(ODesc* d) const;
void InitTimer(double delay);
void DoExpire(double t);
unsigned int MemoryAllocation() const;
void ClearTimer(Timer* t)
{
if ( timer == t )
timer = 0;
}
protected:
friend class Val;
friend class StateAccess;
TableVal() {}
void Init(TableType* t);
void CheckExpireAttr(attr_tag at);
int ExpandCompoundAndInit(val_list* vl, int k, Val* new_val);
int CheckAndAssign(Val* index, Val* new_val, Opcode op = OP_ASSIGN);
HashKey* ComputeHash(const Val* index) const
{ return table_hash->ComputeHash(index, 1); }
bool AddProperties(Properties arg_state);
bool RemoveProperties(Properties arg_state);
// Calculates default value for index. Returns 0 if none.
Val* Default(Val* index);
// Calls &expire_func and returns its return interval;
// takes ownership of the reference.
double CallExpireFunc(Val *idx);
// Propagates a read operation if necessary.
void ReadOperation(Val* index, TableEntryVal *v);
DECLARE_SERIAL(TableVal);
TableType* table_type;
CompositeHash* table_hash;
Attributes* attrs;
double expire_time;
Expr* expire_expr;
TableValTimer* timer;
IterCookie* expire_cookie;
PrefixTable* subnets;
Val* def_val;
};
class RecordVal : public MutableVal {
public:
RecordVal(RecordType* t);
~RecordVal();
Val* SizeVal() const
{ return new Val(record_type->NumFields(), TYPE_COUNT); }
void Assign(int field, Val* new_val, Opcode op = OP_ASSIGN);
Val* Lookup(int field) const; // Does not Ref() value.
Val* LookupWithDefault(int field) const; // Does Ref() value.
void Describe(ODesc* d) const;
// This is an experiment to associate a BroObj within the
// event engine to a record value in bro script.
void SetOrigin(BroObj* o) { origin = o; }
BroObj* GetOrigin() const { return origin; }
// Returns a new value representing the value coerced to the given
// type. If coercion is not possible, returns 0. The non-const
// version may return the current value ref'ed if its type matches
// directly.
//
// *aggr* is optional; if non-zero, we add to it. See
// Expr::InitVal(). We leave it out in the non-const version to make
// the choice unambigious.
//
// The *allow_orphaning* parameter allows for a record to be demoted
// down to a record type that contains less fields.
RecordVal* CoerceTo(const RecordType* other, Val* aggr, bool allow_orphaning = false) const;
RecordVal* CoerceTo(RecordType* other, bool allow_orphaning = false);
unsigned int MemoryAllocation() const;
void DescribeReST(ODesc* d) const;
protected:
friend class Val;
RecordVal() {}
bool AddProperties(Properties arg_state);
bool RemoveProperties(Properties arg_state);
DECLARE_SERIAL(RecordVal);
RecordType* record_type;
BroObj* origin;
};
class EnumVal : public Val {
public:
EnumVal(int i, EnumType* t) : Val(t)
{
val.int_val = i;
type = t;
attribs = 0;
}
Val* SizeVal() const { return new Val(val.int_val, TYPE_INT); }
protected:
friend class Val;
EnumVal() {}
void ValDescribe(ODesc* d) const;
DECLARE_SERIAL(EnumVal);
};
class VectorVal : public MutableVal {
public:
VectorVal(VectorType* t);
~VectorVal();
Val* SizeVal() const
{ return new Val(uint32(val.vector_val->size()), TYPE_COUNT); }
// Returns false if the type of the argument was wrong.
// The vector will automatically grow to accomodate the index.
// 'assigner" is the expression that is doing the assignment;
// it's just used for pinpointing errors.
//
// Note: does NOT Ref() the element! Remember to do so unless
// the element was just created and thus has refcount 1.
//
bool Assign(unsigned int index, Val* element, const Expr* assigner,
Opcode op = OP_ASSIGN);
bool Assign(Val* index, Val* element, const Expr* assigner,
Opcode op = OP_ASSIGN)
{
return Assign(index->AsListVal()->Index(0)->CoerceToUnsigned(),
element, assigner, op);
}
// Assigns the value to how_many locations starting at index.
bool AssignRepeat(unsigned int index, unsigned int how_many,
Val* element, const Expr* assigner);
// Returns nil if no element was at that value.
// Lookup does NOT grow the vector to this size.
// The Val* variant assumes that the index Val* has been type-checked.
Val* Lookup(unsigned int index) const;
Val* Lookup(Val* index)
{
bro_uint_t i = index->AsListVal()->Index(0)->CoerceToUnsigned();
return Lookup(static_cast<unsigned int>(i));
}
unsigned int Size() const { return val.vector_val->size(); }
// Is there any way to reclaim previously-allocated memory when you
// shrink a vector? The return value is the old size.
unsigned int Resize(unsigned int new_num_elements);
// Won't shrink size.
unsigned int ResizeAtLeast(unsigned int new_num_elements);
protected:
friend class Val;
VectorVal() { }
bool AddProperties(Properties arg_state);
bool RemoveProperties(Properties arg_state);
void ValDescribe(ODesc* d) const;
DECLARE_SERIAL(VectorVal);
VectorType* vector_type;
};
// Checks the given value for consistency with the given type. If an
// exact match, returns it. If promotable, returns the promoted version,
// Unref()'ing the original. If not a match, generates an error message
// and returns nil, also Unref()'ing v. If is_init is true, then
// the checking is done in the context of an initialization.
extern Val* check_and_promote(Val* v, const BroType* t, int is_init);
// Given a pointer to where a Val's core (i.e., its BRO value) resides,
// returns a corresponding newly-created or Ref()'d Val. ptr must already
// be properly aligned. Returns the size of the core in bytes in 'n'.
// If t corresponds to a variable-length type, n must give the size on entry.
Val* recover_val(void* ptr, BroType* t, int& n);
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 delete_vals(val_list* vals);
// True if the given Val* has a vector type.
inline bool is_vector(Val* v) { return v->Type()->Tag() == TYPE_VECTOR; }
#endif