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_VOID:
|
||||||
case TYPE_INTERNAL_OTHER:
|
case TYPE_INTERNAL_OTHER:
|
||||||
{
|
{
|
||||||
if ( v->Type()->Tag() == TYPE_FUNC )
|
switch ( v->Type()->Tag() ) {
|
||||||
|
case TYPE_FUNC:
|
||||||
{
|
{
|
||||||
uint32* kp = AlignAndPadType<uint32>(kp0);
|
uint32* kp = AlignAndPadType<uint32>(kp0);
|
||||||
*kp = v->AsFunc()->GetUniqueFuncID();
|
*kp = v->AsFunc()->GetUniqueFuncID();
|
||||||
kp1 = reinterpret_cast<char*>(kp+1);
|
kp1 = reinterpret_cast<char*>(kp+1);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
else if ( v->Type()->Tag() == TYPE_RECORD )
|
case TYPE_RECORD:
|
||||||
{
|
{
|
||||||
char* kp = kp0;
|
char* kp = kp0;
|
||||||
RecordVal* rv = v->AsRecordVal();
|
RecordVal* rv = v->AsRecordVal();
|
||||||
|
@ -187,12 +189,83 @@ char* CompositeHash::SingleValHash(int type_check, char* kp0,
|
||||||
|
|
||||||
kp1 = kp;
|
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");
|
reporter->InternalError("bad index type in CompositeHash::SingleValHash");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_INTERNAL_STRING:
|
case TYPE_INTERNAL_STRING:
|
||||||
|
@ -375,10 +448,14 @@ int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v,
|
||||||
case TYPE_INTERNAL_VOID:
|
case TYPE_INTERNAL_VOID:
|
||||||
case TYPE_INTERNAL_OTHER:
|
case TYPE_INTERNAL_OTHER:
|
||||||
{
|
{
|
||||||
if ( bt->Tag() == TYPE_FUNC )
|
switch ( bt->Tag() ) {
|
||||||
|
case TYPE_FUNC:
|
||||||
|
{
|
||||||
sz = SizeAlign(sz, sizeof(uint32));
|
sz = SizeAlign(sz, sizeof(uint32));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
else if ( bt->Tag() == TYPE_RECORD )
|
case TYPE_RECORD:
|
||||||
{
|
{
|
||||||
const RecordVal* rv = v ? v->AsRecordVal() : 0;
|
const RecordVal* rv = v ? v->AsRecordVal() : 0;
|
||||||
RecordType* rt = bt->AsRecordType();
|
RecordType* rt = bt->AsRecordType();
|
||||||
|
@ -397,12 +474,74 @@ int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v,
|
||||||
return 0;
|
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");
|
reporter->InternalError("bad index type in CompositeHash::CompositeHash");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_INTERNAL_STRING:
|
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_VOID:
|
||||||
case TYPE_INTERNAL_OTHER:
|
case TYPE_INTERNAL_OTHER:
|
||||||
{
|
{
|
||||||
if ( t->Tag() == TYPE_FUNC )
|
switch ( t->Tag() ) {
|
||||||
|
case TYPE_FUNC:
|
||||||
{
|
{
|
||||||
const uint32* const kp = AlignType<uint32>(kp0);
|
const uint32* const kp = AlignType<uint32>(kp0);
|
||||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
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 )
|
pval->Type()->Tag() != TYPE_FUNC )
|
||||||
reporter->InternalError("inconsistent aggregate Val in CompositeHash::RecoverOneVal()");
|
reporter->InternalError("inconsistent aggregate Val in CompositeHash::RecoverOneVal()");
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
else if ( t->Tag() == TYPE_RECORD )
|
case TYPE_RECORD:
|
||||||
{
|
{
|
||||||
const char* kp = kp0;
|
const char* kp = kp0;
|
||||||
RecordType* rt = t->AsRecordType();
|
RecordType* rt = t->AsRecordType();
|
||||||
|
@ -700,11 +841,91 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0,
|
||||||
pval = rv;
|
pval = rv;
|
||||||
kp1 = kp;
|
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");
|
reporter->InternalError("bad index type in CompositeHash::DescribeKey");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_INTERNAL_STRING:
|
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