diff --git a/src/Expr.cc b/src/Expr.cc index 049c0981dd..64be16e595 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -4186,6 +4186,9 @@ RecordCoerceExpr::RecordCoerceExpr(Expr* op, RecordType* r) map[t_i] = i; } + if ( IsError() ) + return; + for ( i = 0; i < map_size; ++i ) { if ( map[i] == -1 ) diff --git a/src/Type.cc b/src/Type.cc index 9aa86da8dc..7fab05673f 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -1971,18 +1971,33 @@ int same_attrs(const Attributes* a1, const Attributes* a2) return (*a1 == *a2); } -int record_promotion_compatible(const RecordType* /* super_rec */, - const RecordType* /* sub_rec */) +int record_promotion_compatible(const RecordType* super_rec, + const RecordType* sub_rec) { -#if 0 - int n = sub_rec->NumFields(); - - for ( int i = 0; i < n; ++i ) + for ( int i = 0; i < sub_rec->NumFields(); ++i ) { - if ( ! super_rec->HasField(sub_rec->FieldName(i)) ) + int o = super_rec->FieldOffset(sub_rec->FieldName(i)); + + if ( o < 0 ) + // Orphaned field. + continue; + + BroType* sub_field_type = sub_rec->FieldType(i); + BroType* super_field_type = super_rec->FieldType(o); + + if ( same_type(sub_field_type, super_field_type) ) + continue; + + if ( sub_field_type->Tag() != TYPE_RECORD ) + return 0; + + if ( super_field_type->Tag() != TYPE_RECORD ) + return 0; + + if ( ! record_promotion_compatible(super_field_type->AsRecordType(), + sub_field_type->AsRecordType()) ) return 0; } -#endif return 1; } diff --git a/testing/btest/Baseline/language.record-coerce-clash/out b/testing/btest/Baseline/language.record-coerce-clash/out new file mode 100644 index 0000000000..9ef4116c7e --- /dev/null +++ b/testing/btest/Baseline/language.record-coerce-clash/out @@ -0,0 +1 @@ +error in /Users/jon/Projects/bro/bro/testing/btest/.tmp/language.record-coerce-clash/record-coerce-clash.bro, line 13: type clash for field "cid" ((coerce [$cid=[$orig_h=1.2.3.4, $orig_p=0/tcp, $resp_h=0.0.0.0, $resp_p=wrong]] to myrec) and record { orig_h:addr; orig_p:port; resp_h:addr; resp_p:string; }) diff --git a/testing/btest/language/record-coerce-clash.bro b/testing/btest/language/record-coerce-clash.bro new file mode 100644 index 0000000000..a0bd6f21ad --- /dev/null +++ b/testing/btest/language/record-coerce-clash.bro @@ -0,0 +1,15 @@ +# @TEST-EXEC-FAIL: bro -b %INPUT >out 2>&1 +# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out +# Record coercion attempt should report mismatched field types. +global wrong = "80/tcp"; + +type myrec: record { + cid: conn_id; +}; + +event bro_init() + { + local mr: myrec; + mr = [$cid = [$orig_h=1.2.3.4,$orig_p=0/tcp,$resp_h=0.0.0.0,$resp_p=wrong]]; + get_port_transport_proto(mr$cid$resp_p); + }