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

@ -2619,7 +2619,17 @@ void IndexExpr::Add(Frame* f)
if ( ! v2 )
return;
v1->AsTableVal()->Assign(std::move(v2), nullptr);
bool iterators_invalidated = false;
v1->AsTableVal()->Assign(std::move(v2), nullptr, true, &iterators_invalidated);
if ( iterators_invalidated )
{
ODesc d;
Describe(&d);
reporter->PushLocation(GetLocationInfo());
reporter->Warning("possible loop/iterator invalidation caused by expression: %s", d.Description());
reporter->PopLocation();
}
}
void IndexExpr::Delete(Frame* f)
@ -2637,7 +2647,17 @@ void IndexExpr::Delete(Frame* f)
if ( ! v2 )
return;
v1->AsTableVal()->Remove(*v2);
bool iterators_invalidated = false;
v1->AsTableVal()->Remove(*v2, true, &iterators_invalidated);
if ( iterators_invalidated )
{
ODesc d;
Describe(&d);
reporter->PushLocation(GetLocationInfo());
reporter->Warning("possible loop/iterator invalidation caused by expression: %s", d.Description());
reporter->PopLocation();
}
}
ExprPtr IndexExpr::MakeLvalue()
@ -2858,7 +2878,10 @@ void IndexExpr::Assign(Frame* f, ValPtr v)
}
case TYPE_TABLE:
if ( ! v1->AsTableVal()->Assign(std::move(v2), std::move(v)) )
{
bool iterators_invalidated = false;
if ( ! v1->AsTableVal()->Assign(std::move(v2), std::move(v), true, &iterators_invalidated) )
{
v = std::move(v_extra);
@ -2876,6 +2899,16 @@ void IndexExpr::Assign(Frame* f, ValPtr v)
else
RuntimeErrorWithCallStack("assignment failed with null value");
}
if ( iterators_invalidated )
{
ODesc d;
Describe(&d);
reporter->PushLocation(GetLocationInfo());
reporter->Warning("possible loop/iterator invalidation caused by expression: %s", d.Description());
reporter->PopLocation();
}
}
break;
case TYPE_STRING: