From a44b056e8148cf1d9cf9826d50e439194ab8ee45 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 17 Sep 2020 21:21:00 -0700 Subject: [PATCH] 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. --- src/parse.y | 30 +++++++++++++++++++ .../Baseline/language.int-negation-range/out | 2 ++ .../btest/language/int-negation-range.zeek | 9 ++++++ 3 files changed, 41 insertions(+) create mode 100644 testing/btest/Baseline/language.int-negation-range/out create mode 100644 testing/btest/language/int-negation-range.zeek diff --git a/src/parse.y b/src/parse.y index d0eeb91300..65d13a438d 100644 --- a/src/parse.y +++ b/src/parse.y @@ -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(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 '!' diff --git a/testing/btest/Baseline/language.int-negation-range/out b/testing/btest/Baseline/language.int-negation-range/out new file mode 100644 index 0000000000..161e8467b5 --- /dev/null +++ b/testing/btest/Baseline/language.int-negation-range/out @@ -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) diff --git a/testing/btest/language/int-negation-range.zeek b/testing/btest/language/int-negation-range.zeek new file mode 100644 index 0000000000..ae7b4ede3f --- /dev/null +++ b/testing/btest/language/int-negation-range.zeek @@ -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;