mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Teach CompHash to allow indexing by records with vector/table/set fields.
Addresses #464.
This commit is contained in:
parent
8eeb37129a
commit
1e4c3d8ea2
3 changed files with 295 additions and 9 deletions
239
src/CompHash.cc
239
src/CompHash.cc
|
@ -155,14 +155,16 @@ char* CompositeHash::SingleValHash(int type_check, char* kp0,
|
|||
case TYPE_INTERNAL_VOID:
|
||||
case TYPE_INTERNAL_OTHER:
|
||||
{
|
||||
if ( v->Type()->Tag() == TYPE_FUNC )
|
||||
switch ( v->Type()->Tag() ) {
|
||||
case TYPE_FUNC:
|
||||
{
|
||||
uint32* kp = AlignAndPadType<uint32>(kp0);
|
||||
*kp = v->AsFunc()->GetUniqueFuncID();
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
}
|
||||
break;
|
||||
|
||||
else if ( v->Type()->Tag() == TYPE_RECORD )
|
||||
case TYPE_RECORD:
|
||||
{
|
||||
char* kp = kp0;
|
||||
RecordVal* rv = v->AsRecordVal();
|
||||
|
@ -187,12 +189,83 @@ char* CompositeHash::SingleValHash(int type_check, char* kp0,
|
|||
|
||||
kp1 = kp;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
case TYPE_TABLE:
|
||||
{
|
||||
int* kp = AlignAndPadType<int>(kp0);
|
||||
TableVal* tv = v->AsTableVal();
|
||||
ListVal* lv = tv->ConvertToList();
|
||||
*kp = tv->Size();
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
for ( int i = 0; i < tv->Size(); ++i )
|
||||
{
|
||||
Val* key = lv->Index(i);
|
||||
if ( ! (kp1 = SingleValHash(type_check, kp1, key->Type(), key,
|
||||
false)) )
|
||||
return 0;
|
||||
if ( ! v->Type()->IsSet() )
|
||||
{
|
||||
Val* val = tv->Lookup(key);
|
||||
if ( ! (kp1 = SingleValHash(type_check, kp1, val->Type(),
|
||||
val, false)) )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_VECTOR:
|
||||
{
|
||||
unsigned int* kp = AlignAndPadType<unsigned int>(kp0);
|
||||
VectorVal* vv = v->AsVectorVal();
|
||||
VectorType* vt = v->Type()->AsVectorType();
|
||||
vector<Val*>* indices = v->AsVector();
|
||||
*kp = vv->Size();
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
for ( unsigned int i = 0; i < vv->Size(); ++i )
|
||||
{
|
||||
Val* val = vv->Lookup(i);
|
||||
unsigned int* kp = AlignAndPadType<unsigned int>(kp1);
|
||||
*kp = i;
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
kp = AlignAndPadType<unsigned int>(kp1);
|
||||
*kp = val ? 1 : 0;
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
|
||||
if ( val )
|
||||
{
|
||||
if ( ! (kp1 = SingleValHash(type_check, kp1,
|
||||
vt->YieldType(), val, false)) )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_LIST:
|
||||
{
|
||||
int* kp = AlignAndPadType<int>(kp0);
|
||||
ListVal* lv = v->AsListVal();
|
||||
*kp = lv->Length();
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
for ( int i = 0; i < lv->Length(); ++i )
|
||||
{
|
||||
Val* v = lv->Index(i);
|
||||
if ( ! (kp1 = SingleValHash(type_check, kp1, v->Type(), v,
|
||||
false)) )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
reporter->InternalError("bad index type in CompositeHash::SingleValHash");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_INTERNAL_STRING:
|
||||
|
@ -375,10 +448,14 @@ int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v,
|
|||
case TYPE_INTERNAL_VOID:
|
||||
case TYPE_INTERNAL_OTHER:
|
||||
{
|
||||
if ( bt->Tag() == TYPE_FUNC )
|
||||
switch ( bt->Tag() ) {
|
||||
case TYPE_FUNC:
|
||||
{
|
||||
sz = SizeAlign(sz, sizeof(uint32));
|
||||
}
|
||||
break;
|
||||
|
||||
else if ( bt->Tag() == TYPE_RECORD )
|
||||
case TYPE_RECORD:
|
||||
{
|
||||
const RecordVal* rv = v ? v->AsRecordVal() : 0;
|
||||
RecordType* rt = bt->AsRecordType();
|
||||
|
@ -397,12 +474,74 @@ int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v,
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
case TYPE_TABLE:
|
||||
{
|
||||
if ( ! v )
|
||||
return (optional && ! calc_static_size) ? sz : 0;
|
||||
|
||||
sz = SizeAlign(sz, sizeof(int));
|
||||
TableVal* tv = const_cast<TableVal*>(v->AsTableVal());
|
||||
ListVal* lv = tv->ConvertToList();
|
||||
for ( int i = 0; i < tv->Size(); ++i )
|
||||
{
|
||||
Val* key = lv->Index(i);
|
||||
sz = SingleTypeKeySize(key->Type(), key, type_check, sz, false,
|
||||
calc_static_size);
|
||||
if ( ! sz ) return 0;
|
||||
if ( ! bt->IsSet() )
|
||||
{
|
||||
Val* val = tv->Lookup(key);
|
||||
sz = SingleTypeKeySize(val->Type(), val, type_check, sz,
|
||||
false, calc_static_size);
|
||||
if ( ! sz ) return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_VECTOR:
|
||||
{
|
||||
if ( ! v )
|
||||
return (optional && ! calc_static_size) ? sz : 0;
|
||||
|
||||
sz = SizeAlign(sz, sizeof(unsigned int));
|
||||
VectorVal* vv = const_cast<VectorVal*>(v->AsVectorVal());
|
||||
for ( unsigned int i = 0; i < vv->Size(); ++i )
|
||||
{
|
||||
Val* val = vv->Lookup(i);
|
||||
sz = SizeAlign(sz, sizeof(unsigned int));
|
||||
sz = SizeAlign(sz, sizeof(unsigned int));
|
||||
if ( val )
|
||||
sz = SingleTypeKeySize(bt->AsVectorType()->YieldType(),
|
||||
val, type_check, sz, false,
|
||||
calc_static_size);
|
||||
if ( ! sz ) return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_LIST:
|
||||
{
|
||||
sz = SizeAlign(sz, sizeof(int));
|
||||
ListVal* lv = const_cast<ListVal*>(v->AsListVal());
|
||||
for ( int i = 0; i < lv->Length(); ++i )
|
||||
{
|
||||
sz = SingleTypeKeySize(lv->Index(i)->Type(), lv->Index(i),
|
||||
type_check, sz, false, calc_static_size);
|
||||
if ( ! sz) return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
reporter->InternalError("bad index type in CompositeHash::CompositeHash");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_INTERNAL_STRING:
|
||||
|
@ -636,7 +775,8 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0,
|
|||
case TYPE_INTERNAL_VOID:
|
||||
case TYPE_INTERNAL_OTHER:
|
||||
{
|
||||
if ( t->Tag() == TYPE_FUNC )
|
||||
switch ( t->Tag() ) {
|
||||
case TYPE_FUNC:
|
||||
{
|
||||
const uint32* const kp = AlignType<uint32>(kp0);
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
|
@ -662,8 +802,9 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0,
|
|||
pval->Type()->Tag() != TYPE_FUNC )
|
||||
reporter->InternalError("inconsistent aggregate Val in CompositeHash::RecoverOneVal()");
|
||||
}
|
||||
break;
|
||||
|
||||
else if ( t->Tag() == TYPE_RECORD )
|
||||
case TYPE_RECORD:
|
||||
{
|
||||
const char* kp = kp0;
|
||||
RecordType* rt = t->AsRecordType();
|
||||
|
@ -700,11 +841,91 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0,
|
|||
pval = rv;
|
||||
kp1 = kp;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
case TYPE_TABLE:
|
||||
{
|
||||
int n;
|
||||
const int* const kp = AlignType<int>(kp0);
|
||||
n = *kp;
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
TableType* tt = t->AsTableType();
|
||||
TableVal* tv = new TableVal(tt);
|
||||
vector<Val*> keys, values;
|
||||
for ( int i = 0; i < n; ++i )
|
||||
{
|
||||
Val* key;
|
||||
kp1 = RecoverOneVal(k, kp1, k_end, tt->Indices(), key, false);
|
||||
keys.push_back(key);
|
||||
if ( ! t->IsSet() )
|
||||
{
|
||||
Val* value;
|
||||
kp1 = RecoverOneVal(k, kp1, k_end, tt->YieldType(), value,
|
||||
false);
|
||||
values.push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
for ( int i = 0; i < n; ++i )
|
||||
tv->Assign(keys[i], t->IsSet() ? 0 : values[i]);
|
||||
|
||||
pval = tv;
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_VECTOR:
|
||||
{
|
||||
unsigned int n;
|
||||
const unsigned int* kp = AlignType<unsigned int>(kp0);
|
||||
n = *kp;
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
VectorType* vt = t->AsVectorType();
|
||||
VectorVal* vv = new VectorVal(vt);
|
||||
for ( unsigned int i = 0; i < n; ++i )
|
||||
{
|
||||
kp = AlignType<unsigned int>(kp1);
|
||||
unsigned int index = *kp;
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
kp = AlignType<unsigned int>(kp1);
|
||||
unsigned int have_val = *kp;
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
Val* value = 0;
|
||||
if ( have_val )
|
||||
kp1 = RecoverOneVal(k, kp1, k_end, vt->YieldType(), value,
|
||||
false);
|
||||
vv->Assign(index, value, 0);
|
||||
}
|
||||
|
||||
pval = vv;
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_LIST:
|
||||
{
|
||||
int n;
|
||||
const int* const kp = AlignType<int>(kp0);
|
||||
n = *kp;
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
TypeList* tl = t->AsTypeList();
|
||||
ListVal* lv = new ListVal(TYPE_ANY);
|
||||
for ( int i = 0; i < n; ++i )
|
||||
{
|
||||
Val* v;
|
||||
BroType* it = (*tl->Types())[i];
|
||||
kp1 = RecoverOneVal(k, kp1, k_end, it, v, false);
|
||||
lv->Append(v);
|
||||
}
|
||||
|
||||
pval = lv;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
reporter->InternalError("bad index type in CompositeHash::DescribeKey");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_INTERNAL_STRING:
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
[1.2.3.4] = {
|
||||
[a=4, tags_v=[0, 1], tags_t={
|
||||
[two] = 2,
|
||||
[one] = 1
|
||||
}, tags_s={
|
||||
b,
|
||||
a
|
||||
}]
|
||||
}
|
||||
}
|
||||
{
|
||||
[a=13, tags_v=[, , 2, 3], tags_t={
|
||||
[four] = 4,
|
||||
[five] = 5
|
||||
}, tags_s={
|
||||
d,
|
||||
c
|
||||
}],
|
||||
[a=4, tags_v=[0, 1], tags_t={
|
||||
[two] = 2,
|
||||
[one] = 1
|
||||
}, tags_s={
|
||||
b,
|
||||
a
|
||||
}]
|
||||
}
|
38
testing/btest/language/record-index-complex-fields.bro
Normal file
38
testing/btest/language/record-index-complex-fields.bro
Normal file
|
@ -0,0 +1,38 @@
|
|||
# @TEST-EXEC: bro -b %INPUT >output
|
||||
# @TEST-EXEC: btest-diff output
|
||||
|
||||
# This test checks whether records with complex fields (tables, sets, vectors)
|
||||
# can be used as table/set indices.
|
||||
|
||||
type MetaData: record {
|
||||
a: count;
|
||||
tags_v: vector of count;
|
||||
tags_t: table[string] of count;
|
||||
tags_s: set[string];
|
||||
};
|
||||
|
||||
global ip_data: table[addr] of set[MetaData] = table();
|
||||
|
||||
global t1_t: table[string] of count = { ["one"] = 1, ["two"] = 2 };
|
||||
global t2_t: table[string] of count = { ["four"] = 4, ["five"] = 5 };
|
||||
|
||||
global t1_v: vector of count = vector();
|
||||
global t2_v: vector of count = vector();
|
||||
t1_v[0] = 0;
|
||||
t1_v[1] = 1;
|
||||
t2_v[2] = 2;
|
||||
t2_v[3] = 3;
|
||||
|
||||
local m: MetaData = [$a=4, $tags_v=t1_v, $tags_t=t1_t, $tags_s=set("a", "b")];
|
||||
local n: MetaData = [$a=13, $tags_v=t2_v, $tags_t=t2_t, $tags_s=set("c", "d")];
|
||||
|
||||
if ( 1.2.3.4 !in ip_data )
|
||||
ip_data[1.2.3.4] = set(m);
|
||||
else
|
||||
add ip_data[1.2.3.4][m];
|
||||
|
||||
print ip_data;
|
||||
|
||||
add ip_data[1.2.3.4][n];
|
||||
|
||||
print ip_data[1.2.3.4];
|
Loading…
Add table
Add a link
Reference in a new issue