diff --git a/src/CompHash.cc b/src/CompHash.cc index 148c8384ee..57afdcefa4 100644 --- a/src/CompHash.cc +++ b/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(kp0); *kp = v->AsFunc()->GetUniqueFuncID(); kp1 = reinterpret_cast(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(kp0); + TableVal* tv = v->AsTableVal(); + ListVal* lv = tv->ConvertToList(); + *kp = tv->Size(); + kp1 = reinterpret_cast(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(kp0); + VectorVal* vv = v->AsVectorVal(); + VectorType* vt = v->Type()->AsVectorType(); + vector* indices = v->AsVector(); + *kp = vv->Size(); + kp1 = reinterpret_cast(kp+1); + for ( unsigned int i = 0; i < vv->Size(); ++i ) + { + Val* val = vv->Lookup(i); + unsigned int* kp = AlignAndPadType(kp1); + *kp = i; + kp1 = reinterpret_cast(kp+1); + kp = AlignAndPadType(kp1); + *kp = val ? 1 : 0; + kp1 = reinterpret_cast(kp+1); + + if ( val ) + { + if ( ! (kp1 = SingleValHash(type_check, kp1, + vt->YieldType(), val, false)) ) + return 0; + } + } + } + break; + + case TYPE_LIST: + { + int* kp = AlignAndPadType(kp0); + ListVal* lv = v->AsListVal(); + *kp = lv->Length(); + kp1 = reinterpret_cast(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(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(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(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(kp0); kp1 = reinterpret_cast(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(kp0); + n = *kp; + kp1 = reinterpret_cast(kp+1); + TableType* tt = t->AsTableType(); + TableVal* tv = new TableVal(tt); + vector 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(kp0); + n = *kp; + kp1 = reinterpret_cast(kp+1); + VectorType* vt = t->AsVectorType(); + VectorVal* vv = new VectorVal(vt); + for ( unsigned int i = 0; i < n; ++i ) + { + kp = AlignType(kp1); + unsigned int index = *kp; + kp1 = reinterpret_cast(kp+1); + kp = AlignType(kp1); + unsigned int have_val = *kp; + kp1 = reinterpret_cast(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(kp0); + n = *kp; + kp1 = reinterpret_cast(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: diff --git a/testing/btest/Baseline/language.record-index-complex-fields/output b/testing/btest/Baseline/language.record-index-complex-fields/output new file mode 100644 index 0000000000..21591bc210 --- /dev/null +++ b/testing/btest/Baseline/language.record-index-complex-fields/output @@ -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 +}] +} diff --git a/testing/btest/language/record-index-complex-fields.bro b/testing/btest/language/record-index-complex-fields.bro new file mode 100644 index 0000000000..ae45648728 --- /dev/null +++ b/testing/btest/language/record-index-complex-fields.bro @@ -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];