diff --git a/src/Val.cc b/src/Val.cc index 2b577f58e3..101ff4b983 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -1216,6 +1216,7 @@ Val* PatternVal::DoClone(CloneState* state) { // TODO: Double-check auto re = new RE_Matcher(val.re_val->PatternText(), val.re_val->AnywherePatternText()); + re->Compile(); return new PatternVal(re); } @@ -2557,7 +2558,14 @@ Val* TableVal::DoClone(CloneState* state) while ( (val = tbl->NextEntry(key, cookie)) ) { Val* idx = RecoverIndex(key); - TableEntryVal* nval = val ? new TableEntryVal(*val) : nullptr; + TableEntryVal* nval = nullptr; + if ( val ) + { + if ( val->Value() ) + nval = new TableEntryVal(val->Value()->Clone()); + else + nval = new TableEntryVal(nullptr); + } tv->AsNonConstTable()->Insert(key, nval); if ( subnets ) @@ -3175,17 +3183,22 @@ void RecordVal::DescribeReST(ODesc* d) const Val* RecordVal::DoClone(CloneState* state) { - // TODO: We leave origin unset, ok? + // We set origin to 0 here. + // Origin only seems to be used for exactly one purpose - to find the connection record that is associated + // with a record. As we cannot guarantee that it will ber zeroed out at the approproate time (as it seems to be + // guaranteed for the original record) we don't touch it. ::Ref(record_type); auto rv = new RecordVal(record_type); + rv->origin = nullptr; + rv->val.val_list_val = new val_list(val.val_list_val->length()); loop_over_list(*val.val_list_val, i) { - Val* v = (*val.val_list_val)[i]->Clone(state); + Val* v = (*val.val_list_val)[i] ? (*val.val_list_val)[i]->Clone(state) : nullptr; rv->val.val_list_val->append(v); } - return nullptr; + return rv; } IMPLEMENT_SERIAL(RecordVal, SER_RECORD_VAL); diff --git a/testing/btest/language/copy-all-types.zeek b/testing/btest/language/copy-all-types.zeek index e39308b8e0..515f83dce4 100644 --- a/testing/btest/language/copy-all-types.zeek +++ b/testing/btest/language/copy-all-types.zeek @@ -1,6 +1,56 @@ -# @TEST-EXEC: bro -b %INPUT >out +# @TEST-EXEC: zeek -b %INPUT >out # @TEST-EXEC: btest-diff out +type MyEnum: enum { ENUMME }; + +type InnerTestRecord: record { + a: string; +}; + +type TestRecord: record { + s1: string; + s2: string; + i1: InnerTestRecord; + i2: InnerTestRecord &optional; + donotset: InnerTestRecord &optional; + def: count &default=5; +}; + +function join_count_set(ss: set[count], j: string): string + { + local output=""; + local i=0; + for ( s in ss ) + { + if ( i > 0 ) + output = cat(output, j); + + output = cat(output, s); + ++i; + } + return output; + } + +function do_format(i: any): any + { + local tpe = type_name(i); + + switch ( tpe ) + { + case "set[count]": + return join_count_set(i, ","); + case "table[string] of string": + local cast: table[string] of string = i; + local vout: vector of string = vector(); + for ( el in cast ) + { + vout += cat(el, "=", cast[el]); + } + return join_string_vec(vout, ";"); + } + return i; + } + function check(o1: any, o2: any, equal: bool, expect_same: bool) { local expect_msg = (equal ? "ok" : "FAIL0"); @@ -11,17 +61,126 @@ function check(o1: any, o2: any, equal: bool, expect_same: bool) if ( ! expect_same && same ) expect_msg = "FAIL2"; - - print fmt("orig=%s (%s) clone=%s (%s) equal=%s same_object=%s (%s)", o1, type_name(o1), o2, type_name(o2), equal, same, expect_msg); + + print fmt("orig=%s (%s) clone=%s (%s) equal=%s same_object=%s (%s)", do_format(o1), type_name(o1), do_format(o2), type_name(o2), equal, same, expect_msg); } +function check_vector_equal(a: vector of count, b: vector of count): bool + { + if ( |a| != |b| ) + return F; + + for ( i in a ) + { + if ( a[i] != b[i] ) + return F; + } + + return T; + } + +function check_string_table_equal(a: table[string] of string, b: table[string] of string): bool + { + if ( |a| != |b| ) + return F; + + for ( i in a ) + { + if ( a[i] != b[i] ) + return F; + } + + return T; + } + +function compare_otr(a: TestRecord, b: TestRecord): bool + { + if ( a$s1 != b$s1 ) + return F; + if ( a$s2 != b$s2 ) + return F; + if ( a$i1$a != b$i1$a ) + return F; + if ( a$i2$a != b$i2$a ) + return F; + + if ( same_object(a$i1, b$i1) ) + return F; + if ( same_object(a$i2, b$i2) ) + return F; + + # check that we restroe that i1 & i2 point to same object + if ( ! same_object(a$i1, a$i2) ) + return F; + if ( ! same_object(b$i1, b$i2) ) + return F; + + if ( a$def != b$def ) + return F; + + return T; + } + + event zeek_init() { local i1 = -42; local i2 = copy(i1); check(i1, i2, i1 == i2, T); - + + local c1 : count = 42; + local c2 = copy(c1); + check(c1, c2, c1 == c2, T); + + local a1 = 127.0.0.1; + local a2 = copy(a1); + check(a1, a2, a1 == a2, T); + + local p1 = 42/tcp; + local p2 = copy(p1); + check(p1, p2, p1 == p2, T); + + local sn1 = 127.0.0.1/24; + local sn2 = copy(sn1); + check(sn1, sn2, sn1 == sn2, T); + local s1 = "Foo"; local s2 = copy(s1); check(s1, s2, s1 == s2, F); + + local pat1 = /.*PATTERN.*/; + local pat2 = copy(pat1); + # patterns cannot be directoy compared + if ( same_object(pat1, pat2) ) + print "FAIL P1"; + if ( ! ( pat1 == "PATTERN" ) ) + print "FAIL P2"; + if ( ! ( pat2 == "PATTERN" ) ) + print "FAIL P3"; + if ( pat2 == "PATERN" ) + print "FAIL P4"; + print fmt("orig=%s (%s) clone=%s (%s) same_object=%s", pat1, type_name(pat1), pat2, type_name(pat2), same_object(pat1, pat2)); + + local set1 = [1, 2, 3, 4, 5]; + local set2 = copy(set1); + check(set1, set2, set1 == set2, F); + + local v1 = vector(1, 2, 3, 4, 5); + local v2 = copy(v1); + check(v1, v2, check_vector_equal(v1, v2), F); + + local t1 : table[string] of string = table(); + t1["a"] = "va"; + t1["b"] = "vb"; + local t2 = copy(t1); + check(t1, t2, check_string_table_equal(t1, t2), F); + + local e1 = ENUMME; + local e2 = copy(ENUMME); + check(e1, e2, e1 == e2, T); + + local itr = InnerTestRecord($a="a"); + local otr1 = TestRecord($s1="s1", $s2="s2", $i1=itr, $i2=itr); + local otr2 = copy(otr1); + check(otr1, otr2, compare_otr(otr1, otr2), F); }