Teach CompHash to allow indexing by records with vector/table/set fields.

Addresses #464.
This commit is contained in:
Jon Siwek 2012-01-20 16:54:48 -06:00
parent 8eeb37129a
commit 1e4c3d8ea2
3 changed files with 295 additions and 9 deletions

View file

@ -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:

View file

@ -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
}]
}

View 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];