GH-1328: Improve behavior of Dictionary iterator invalidation

Previously, an assertion was triggered in debug builds upon any attempt
to insert or remove a Dictionary entry while any iteration of that
Dictionary is underway and also even in cases where Dictionary membership
was not actually modified (and thus invalidates a loop).

Now, it emits run-time warnings regardless of build-type and only when
insert/remove operations truly change the Dictionary membership.  In the
context of a Zeek script causing an invalidation, the warning message
also now helps pinpoint the exact expression that causes it.
This commit is contained in:
Jon Siwek 2020-12-11 18:39:44 -08:00
parent 9d8bab692c
commit 8f98b068c8
7 changed files with 287 additions and 35 deletions

View file

@ -0,0 +1,73 @@
# @TEST-EXEC: zeek -b %INPUT >out 2>&1
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out
# Note that while modifying container membership during for-loop iteration is
# supposed to be undefined-behavior, it should be practically ok to have this
# test perform such operations if they always `break` out of the loop
# immediately afterward.
local t = table([1] = "one", [2] = "two", [3] = "three");
for ( i in t )
# Modifying an existing element is not qualified an modifying membership,
# so this doesn't trigger a warning.
t[i] = cat(i);
print t;
for ( i in t )
{
# Adding an element in a loop should trigger a warning.
t[4] = "four";
break;
}
print t;
for ( i in t )
{
# Deleting an element in a loop should trigger a warning.
delete t[4];
break;
}
print t;
for ( i in t )
# Trying to delete a non-existent element within in a loop does not
# actually modify membership, so does not trigger a warning.
delete t[0];
print t;
local s = set(1, 2, 3);
for ( n in s )
# Trying to add an existing element within in a loop does not
# actually modify membership, so does not trigger a warning.
add s[1];
for ( n in s )
{
# Adding an element in a loop should trigger a warning.
add s[4];
break;
}
print s;
for ( n in s )
{
# Deleting an element in a loop should trigger a warning.
delete s[4];
break;
}
print s;
for ( n in s )
# Trying to delete a non-existent element within in a loop does not
# actually modify membership, so does not trigger a warning.
delete s[0];
print s;