GH-219: fix |x| operator int overflow / floating point type inconsistency

When 'x' is an integral arithmetic expression, it's now coerced to
yield a signed integer before taking the absolute value of it to
prevent the common issue of unsigned integer overflow/wraparound for
values below zero.

Using a time or interval value/expression for 'x' now also yields a
time or interval, respective, from the |x| operation instead of
a double.
This commit is contained in:
Jon Siwek 2019-01-22 16:42:40 -06:00
parent bebc0fba6d
commit 3256ac7c49
8 changed files with 21 additions and 6 deletions

View file

@ -1360,6 +1360,9 @@ SizeExpr::SizeExpr(Expr* arg_op) : UnaryExpr(EXPR_SIZE, arg_op)
if ( IsError() ) if ( IsError() )
return; return;
if ( op->Type()->InternalType() == TYPE_INTERNAL_DOUBLE )
SetType(op->Type()->Ref());
else
SetType(base_type(TYPE_COUNT)); SetType(base_type(TYPE_COUNT));
} }

View file

@ -425,7 +425,7 @@ Val* Val::SizeVal() const
return val_mgr->GetCount(val.uint_val); return val_mgr->GetCount(val.uint_val);
case TYPE_INTERNAL_DOUBLE: case TYPE_INTERNAL_DOUBLE:
return new Val(fabs(val.double_val), TYPE_DOUBLE); return new Val(fabs(val.double_val), type->Tag());
case TYPE_INTERNAL_OTHER: case TYPE_INTERNAL_OTHER:
if ( type->Tag() == TYPE_FUNC ) if ( type->Tag() == TYPE_FUNC )

View file

@ -728,7 +728,12 @@ expr:
| '|' expr '|' %prec '(' | '|' expr '|' %prec '('
{ {
set_location(@1, @3); set_location(@1, @3);
$$ = new SizeExpr($2); auto e = $2;
if ( IsIntegral(e->Type()->Tag()) )
e = new ArithCoerceExpr(e, TYPE_INT);
$$ = new SizeExpr(e);
} }
| expr TOK_AS type | expr TOK_AS type

View file

@ -15,6 +15,7 @@ add different time units (PASS)
subtract different time units (PASS) subtract different time units (PASS)
absolute value (PASS) absolute value (PASS)
absolute value (PASS) absolute value (PASS)
absolute value (PASS)
assignment operator (PASS) assignment operator (PASS)
assignment operator (PASS) assignment operator (PASS)
multiplication operator (PASS) multiplication operator (PASS)

View file

@ -2,6 +2,7 @@ IPv4 Address 1.2.3.4: 32
IPv6 Address ::1: 128 IPv6 Address ::1: 128
Boolean T: 1 Boolean T: 1
Count 10: 10 Count 10: 10
Expr: 4
Double -1.23: 1.230000 Double -1.23: 1.230000
Enum ENUM3: 2 Enum ENUM3: 2
File 21.000000 File 21.000000

View file

@ -70,8 +70,9 @@ event bro_init()
test_case( "compare different time units", in13 >= in35 ); test_case( "compare different time units", in13 >= in35 );
test_case( "add different time units", in13 + in14 == 4min ); test_case( "add different time units", in13 + in14 == 4min );
test_case( "subtract different time units", in24 - in23 == 0sec ); test_case( "subtract different time units", in24 - in23 == 0sec );
test_case( "absolute value", |in25| == 2.0*3600 ); test_case( "absolute value", |in25| == 2hr );
test_case( "absolute value", |in36| == 2.5*86400 ); test_case( "absolute value", |in36| == 2.5day );
test_case( "absolute value", |5sec - 9sec| == 4sec );
in34 += 2hr; in34 += 2hr;
test_case( "assignment operator", in34 == 122min ); test_case( "assignment operator", in34 == 122min );
in34 -= 2hr; in34 -= 2hr;

View file

@ -64,6 +64,10 @@ print fmt("Boolean %s: %d", b, |b|);
# Size of count: identity. # Size of count: identity.
print fmt("Count %s: %d", c, |c|); print fmt("Count %s: %d", c, |c|);
# Size of integral arithmetic expression should coerce to int before absolute
# value operation to help prevent common unsigned int overflow situations.
print fmt("Expr: %d", |5 - 9|);
# Size of double: returns absolute value. # Size of double: returns absolute value.
print fmt("Double %s: %f", d, |d|); print fmt("Double %s: %f", d, |d|);

View file

@ -27,7 +27,7 @@ event bro_init()
test_case( "inequality", t1 != t3 ); test_case( "inequality", t1 != t3 );
test_case( "equality", t1 == t4 ); test_case( "equality", t1 == t4 );
test_case( "subtract time", t2 - t1 == 3sec); test_case( "subtract time", t2 - t1 == 3sec);
test_case( "size operator", |t5| == 1234567890.0 ); test_case( "size operator", |t5| == t5 );
} }