Improve negation of ConstExpr

* Instead of creating a NegExpr for negation of a literal/constant,
  a ConstExpr is now created directly.

* For negation of integer literals, there's now an additional check
  for whether the integer would be outside the range of possible 'int'
  values.  This can also help prevent the undefined behavior due to
  overflow as a result of trying to represent the minimum 'int' value of
  -9223372036854775808 as a literal in a script -- the unsigned value is
  cast to signed yielding INT64_MIN, then INT64_MIN is negated.
This commit is contained in:
Jon Siwek 2020-09-17 21:21:00 -07:00
parent 1b88e63e78
commit a44b056e81
3 changed files with 41 additions and 0 deletions

View file

@ -330,6 +330,36 @@ expr:
{
zeek::detail::set_location(@1, @2);
$$ = new zeek::detail::NegExpr({zeek::AdoptRef{}, $2});
if ( ! $$->IsError() && $2->IsConst() )
{
auto v = $2->ExprVal();
auto tag = v->GetType()->Tag();
if ( tag == zeek::TYPE_COUNT )
{
auto c = v->AsCount();
uint64_t int_max = static_cast<uint64_t>(INT64_MAX) + 1;
if ( c <= int_max )
{
auto ce = new zeek::detail::ConstExpr(zeek::val_mgr->Int(-c));
Unref($$);
$$ = ce;
}
else
{
$$->Error("literal is outside range of 'int' values");
$$->SetError();
}
}
else
{
auto ce = new zeek::detail::ConstExpr($$->Eval(nullptr));
Unref($$);
$$ = ce;
}
}
}
| '+' expr %prec '!'

View file

@ -0,0 +1,2 @@
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.int-negation-range/int-negation-range.zeek, line 8: literal is outside range of 'int' values (-9223372036854775809)
error in /home/jon/pro/zeek/zeek/testing/btest/.tmp/language.int-negation-range/int-negation-range.zeek, line 9: literal is outside range of 'int' values (-9223372036854775810)

View file

@ -0,0 +1,9 @@
# @TEST-EXEC-FAIL: zeek -b %INPUT >out 2>&1
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff out
local i_min = -9223372036854775808;
local i_min_p1 = -9223372036854775807;
# These should be caught at parse-time as outside the range of a 64-bit ints.
local i_min_m1 = -9223372036854775809;
local i_min_m2 = -9223372036854775810;