Fix memory leak in vector slice assignment

Two parts to this:

  * Only allow vector slice assignment in statement contexts, not in
    arbitrary assignment expressions.  E.g. it's not clear what the
    resulting value of `(v[1:2] = vector(1))` is for further expression
    chaining.  For reference, Python doesn't allow it either.

  * Add a subclass of AssignExpr to specialize the behavior for index
    slice assignments (because its behavior regarding expression
    chaining is different per the previous point) and Unref the RHS
    of things like `v[1:2] = vector(1)` after IndexExpr::Assign is
    finished inserting it (since no one else takes ownership of it).

Instead of using an Expr subclass, IndexSliceAssignExpr, we could
use a proper Stmt, since that's the only context we currently use it
for, but if we did ever to decide on allowing its use in arbitrary
expression contexts, then I expect we'll need it this way anyway
(just with a different IndexSliceAssignExpr::Eval implementation).
This commit is contained in:
Jon Siwek 2019-06-18 17:42:06 -07:00
parent 91835752b7
commit 385f500497
5 changed files with 140 additions and 21 deletions

View file

@ -32,7 +32,7 @@ const char* expr_name(BroExprTag t)
"$=", "in", "<<>>",
"()", "event", "schedule",
"coerce", "record_coerce", "table_coerce",
"sizeof", "flatten", "cast", "is"
"sizeof", "flatten", "cast", "is", "[:]="
};
if ( int(t) >= NUM_EXPRS )
@ -2905,8 +2905,46 @@ bool AssignExpr::DoUnserialize(UnserialInfo* info)
return UNSERIALIZE(&is_init);
}
IndexExpr::IndexExpr(Expr* arg_op1, ListExpr* arg_op2, bool is_slice)
: BinaryExpr(EXPR_INDEX, arg_op1, arg_op2)
IndexSliceAssignExpr::IndexSliceAssignExpr(Expr* op1, Expr* op2, int is_init)
: AssignExpr(op1, op2, is_init)
{
}
Val* IndexSliceAssignExpr::Eval(Frame* f) const
{
if ( is_init )
{
RuntimeError("illegal assignment in initialization");
return 0;
}
Val* v = op2->Eval(f);
if ( v )
{
op1->Assign(f, v);
Unref(v);
}
return 0;
}
IMPLEMENT_SERIAL(IndexSliceAssignExpr, SER_INDEX_SLICE_ASSIGN_EXPR);
bool IndexSliceAssignExpr::DoSerialize(SerialInfo* info) const
{
DO_SERIALIZE(SER_INDEX_SLICE_ASSIGN_EXPR, AssignExpr);
return true;
}
bool IndexSliceAssignExpr::DoUnserialize(UnserialInfo* info)
{
DO_UNSERIALIZE(AssignExpr);
return true;
}
IndexExpr::IndexExpr(Expr* arg_op1, ListExpr* arg_op2, bool arg_is_slice)
: BinaryExpr(EXPR_INDEX, arg_op1, arg_op2), is_slice(arg_is_slice)
{
if ( IsError() )
return;
@ -3302,13 +3340,13 @@ IMPLEMENT_SERIAL(IndexExpr, SER_INDEX_EXPR);
bool IndexExpr::DoSerialize(SerialInfo* info) const
{
DO_SERIALIZE(SER_INDEX_EXPR, BinaryExpr);
return true;
return SERIALIZE(is_slice);
}
bool IndexExpr::DoUnserialize(UnserialInfo* info)
{
DO_UNSERIALIZE(BinaryExpr);
return true;
return UNSERIALIZE(&is_slice);
}
FieldExpr::FieldExpr(Expr* arg_op, const char* arg_field_name)
@ -5747,6 +5785,8 @@ Expr* get_assign_expr(Expr* op1, Expr* op2, int is_init)
if ( op1->Type()->Tag() == TYPE_RECORD &&
op2->Type()->Tag() == TYPE_LIST )
return new RecordAssignExpr(op1, op2, is_init);
else if ( op1->Tag() == EXPR_INDEX && op1->AsIndexExpr()->IsSlice() )
return new IndexSliceAssignExpr(op1, op2, is_init);
else
return new AssignExpr(op1, op2, is_init);
}