CompositeHash: Skip record initialization when recovering vals

Initializing fields of recovered records caused running &default expression
of fields just so that they are re-assigned in the next step with the
recovered fields. The second test case still shows that the loop var
is initialized as well even though that's not needed.

Add tests for iterating over records with &default attributes for both,
tables and vectors.

Fixes #3267
This commit is contained in:
Arne Welzel 2023-09-01 18:18:31 +02:00
parent 057bc673a8
commit aaa81cae5d
9 changed files with 229 additions and 2 deletions

View file

@ -359,10 +359,11 @@ bool CompositeHash::RecoverOneVal(const HashKey& hk, Type* t, ValPtr* pval, bool
ASSERT(int(values.size()) == num_fields);
auto rv = make_intrusive<RecordVal>(IntrusivePtr{NewRef{}, rt});
auto rv = make_intrusive<RecordVal>(IntrusivePtr{NewRef{}, rt},
false /* init_fields */);
for ( int i = 0; i < num_fields; ++i )
rv->Assign(i, std::move(values[i]));
rv->AppendField(std::move(values[i]), rt->GetFieldType(i));
*pval = std::move(rv);
}

View file

@ -1444,6 +1444,7 @@ protected:
friend class zeek::detail::ValTrace;
friend class zeek::detail::ZBody;
friend class zeek::detail::CPPRuntime;
friend class zeek::detail::CompositeHash;
RecordValPtr DoCoerceTo(RecordTypePtr other, bool allow_orphaning) const;

View file

@ -0,0 +1,14 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
0, done parsing
0, my_seq() invoked
1, populating table, expecting 4 my_seq() invocations
1, my_seq() invoked
2, my_seq() invoked
3, my_seq() invoked
4, my_seq() invoked
5, iterating table, expecting no my_seq() invocations
5, it, [id=4], 3
5, it, [id=5], 4
5, it, [id=3], 2
5, it, [id=2], 1
5, done

View file

@ -0,0 +1,19 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
0, done parsing
0, my_seq() invoked
1, my_seq() invoked
2, populating table, expecting 8 my_seq() invocations
2, my_seq() invoked
3, my_seq() invoked
4, my_seq() invoked
5, my_seq() invoked
6, my_seq() invoked
7, my_seq() invoked
8, my_seq() invoked
9, my_seq() invoked
10, iterating table, expecting no my_seq() invocations
10, it, [id=8], [id=7]
10, it, [id=6], [id=5]
10, it, [id=4], [id=3]
10, it, [id=10], [id=9]
10, done

View file

@ -0,0 +1,12 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
0, populating table, expecting 4 my_seq() invocations
0, my_seq() invoked
1, my_seq() invoked
2, my_seq() invoked
3, my_seq() invoked
4, iterating table, expecting no my_seq() invocations
4, it, [id=1], 1
4, it, [id=4], 4
4, it, [id=3], 3
4, it, [id=2], 2
4, done

View file

@ -0,0 +1,14 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
0, done parsing
0, my_seq() invoked
1, populating vector, expecting 4 my_seq() invocations
1, my_seq() invoked
2, my_seq() invoked
3, my_seq() invoked
4, my_seq() invoked
5, iterating vector, expecting no my_seq() invocations
5, it, 0, [id=2]
5, it, 1, [id=3]
5, it, 2, [id=4]
5, it, 3, [id=5]
5, done

View file

@ -0,0 +1,12 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
0, populating vector, expecting 4 my_seq() invocations
0, my_seq() invoked
1, my_seq() invoked
2, my_seq() invoked
3, my_seq() invoked
4, iterating vector, expecting no my_seq() invocations
4, it, 0, [id=1]
4, it, 1, [id=2]
4, it, 2, [id=3]
4, it, 3, [id=4]
4, done

View file

@ -0,0 +1,95 @@
# @TEST-DOC: Iterating over tables with record keys would previously evaluate &default during each iteration. Ensure this isn't happening. Regression test for #3267.
# @TEST-EXEC: zeek -b %INPUT >output
# @TEST-EXEC: btest-diff output
global seq = 0;
function my_seq(): count {
print seq, "my_seq() invoked";
return ++seq;
}
type R: record {
id: count &default=my_seq();
};
global tbl: table[R] of count;
print seq, "populating table, expecting 4 my_seq() invocations";
tbl[R()] = 1;
tbl[R()] = 2;
tbl[R()] = 3;
tbl[R()] = 4;
print seq, "iterating table, expecting no my_seq() invocations";
for ( [r], c in tbl )
print seq, "it", r, c;
print seq, "done";
# @TEST-START-NEXT
#
# This acts subtly different - my_seq() is called maybe for the [r] local
# in the for loop?!
global seq = 0;
function my_seq(): count {
print seq, "my_seq() invoked";
return ++seq;
}
type R: record {
id: count &default=my_seq();
};
global tbl: table[R] of count;
event zeek_init()
{
print seq, "populating table, expecting 4 my_seq() invocations";
tbl[R()] = 1;
tbl[R()] = 2;
tbl[R()] = 3;
tbl[R()] = 4;
print seq, "iterating table, expecting no my_seq() invocations";
for ( [r], c in tbl )
print seq, "it", r, c;
print seq, "done";
}
print seq, "done parsing";
# @TEST-START-NEXT
#
# table[R] of R
global seq = 0;
function my_seq(): count {
print seq, "my_seq() invoked";
return ++seq;
}
type R: record {
id: count &default=my_seq();
};
global tbl: table[R] of R;
event zeek_init()
{
print seq, "populating table, expecting 8 my_seq() invocations";
tbl[R()] = R();
tbl[R()] = R();
tbl[R()] = R();
tbl[R()] = R();
print seq, "iterating table, expecting no my_seq() invocations";
for ( [r1], r2 in tbl )
print seq, "it", r1, r2;
print seq, "done";
}
print seq, "done parsing";

View file

@ -0,0 +1,59 @@
# @TEST-DOC: Iterating over vectors holding record. This mirrors table-iterate-record-key-default, but for vectors. They didn't have the same issue. Regression test for #3267.
# @TEST-EXEC: zeek -b %INPUT >output
# @TEST-EXEC: btest-diff output
global seq = 0;
function my_seq(): count {
print seq, "my_seq() invoked";
return ++seq;
}
type R: record {
id: count &default=my_seq();
};
global vec: vector of R;
print seq, "populating vector, expecting 4 my_seq() invocations";
vec += R();
vec += R();
vec += R();
vec += R();
print seq, "iterating vector, expecting no my_seq() invocations";
for ( i, r in vec )
print seq, "it", i, r;
print seq, "done";
# @TEST-START-NEXT
#
# Same as above, but populate / iterate record in zeek_init.
global seq = 0;
function my_seq(): count {
print seq, "my_seq() invoked";
return ++seq;
}
type R: record {
id: count &default=my_seq();
};
global vec: vector of R;
event zeek_init()
{
print seq, "populating vector, expecting 4 my_seq() invocations";
vec += R();
vec += R();
vec += R();
vec += R();
print seq, "iterating vector, expecting no my_seq() invocations";
for ( i, r in vec )
print seq, "it", i, r;
print seq, "done";
}
print seq, "done parsing";