Expr: Warn on count underflow for c -= 1 and c = c - 1

I've skipped treating overflows as warnings, as ++ wrapping around at 0
doesn't currently trigger a runtime error and might be expected to be
quiet and silently wrap.

Closes #2486
This commit is contained in:
Arne Welzel 2022-11-29 15:58:36 +01:00
parent a07b0c333f
commit e48618e244
7 changed files with 67 additions and 2 deletions

9
NEWS
View file

@ -146,6 +146,15 @@ Changed Functionality
stopped. This fixes a few cases where we already had the logic to stopped. This fixes a few cases where we already had the logic to
continue in place, but we still ended up considering them partial. continue in place, but we still ended up considering them partial.
- Count underflows via ``--c`` or subtract from statements (``c = c - 1``) are
now consistently warned about. Previously, underflows through ``--c`` were
treated as runtime errors, while "subtract from" underflows were silently
accepted. The following (surprising behavior) now causes a warning, too:
$ zeek -e 'print 1 - 2'
expression warning in <command line>, line 1: count underflow (1 - 2)
18446744073709551615
Deprecated Functionality Deprecated Functionality
------------------------ ------------------------

View file

@ -888,6 +888,10 @@ ValPtr BinaryExpr::Fold(Val* v1, Val* v2) const
case EXPR_SUB: case EXPR_SUB:
case EXPR_REMOVE_FROM: case EXPR_REMOVE_FROM:
DO_FOLD(-); DO_FOLD(-);
// When subtracting and the result is larger than the left
// operand we mostly likely underflowed and log a warning.
if ( is_unsigned && u3 > u1 )
reporter->ExprRuntimeWarning(this, "count underflow");
break; break;
case EXPR_TIMES: case EXPR_TIMES:
DO_FOLD(*); DO_FOLD(*);
@ -1447,7 +1451,7 @@ ValPtr IncrExpr::DoSingleEval(Frame* f, Val* v) const
--k; --k;
if ( k < 0 && v->GetType()->InternalType() == TYPE_INTERNAL_UNSIGNED ) if ( k < 0 && v->GetType()->InternalType() == TYPE_INTERNAL_UNSIGNED )
RuntimeError("count underflow"); reporter->ExprRuntimeWarning(this, "count underflow");
} }
const auto& ret_type = IsVector(GetType()->Tag()) ? GetType()->Yield() : GetType(); const auto& ret_type = IsVector(GetType()->Tag()) ? GetType()->Yield() : GetType();

View file

@ -0,0 +1,5 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
expression warning in <...>/count-underflow.zeek, line 10: count underflow (--c1)
expression warning in <...>/count-underflow.zeek, line 14: count underflow (c2 - 1)
expression warning in <...>/count-underflow.zeek, line 18: count underflow (c3 - 1)
expression warning in <...>/count-underflow.zeek, line 22: count underflow (1 - 2)

View file

@ -0,0 +1,8 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
local c1 = 0; --c1; c1 == 18446744073709551615; T
local c2 = 0; c2 -= 1; c2 == 18446744073709551615; T
local c3 = 0; c3 = c3 - 1; c3 == 18446744073709551615; T
1 - 2, 18446744073709551615
local c4 = count_max; ++c4; c4 == 0; T
local c5 = count_max; c5 += 1; c5 == 0; T
local c6 = count_max; c6 = c6 + 1; c6 == 0; T

View file

@ -0,0 +1,2 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
expression warning in <...>/sizeof.zeek, line 73: count underflow (5 - 9)

View file

@ -0,0 +1,36 @@
# @TEST-EXEC: zeek -b %INPUT >out
# @TEST-EXEC: btest-diff out
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff .stderr
global count_max: count = 0xffffffffffffffff;
event zeek_init()
{
local c1 = 0;
--c1;
print fmt("local c1 = 0; --c1; c1 == %s; %s", c1, c1 == count_max);
local c2 = 0;
c2 -= 1;
print fmt("local c2 = 0; c2 -= 1; c2 == %s; %s", c2, c2 == count_max);
local c3 = 0;
c3 = c3 - 1;
print fmt("local c3 = 0; c3 = c3 - 1; c3 == %s; %s", c3, c3 == count_max);
# This also triggers a warning now;
print "1 - 2", 1 - 2;
# The following ones all overflow back to 0, but do not log a warning.
local c4 = count_max;
++c4;
print fmt("local c4 = count_max; ++c4; c4 == %s; %s", c4, c4 == 0);
local c5 = count_max;
c5 += 1;
print fmt("local c5 = count_max; c5 += 1; c5 == %s; %s", c5, c5 == 0);
local c6 = count_max;
c6 = c6 + 1;
print fmt("local c6 = count_max; c6 = c6 + 1; c6 == %s; %s", c6, c6 == 0);
}

View file

@ -1,5 +1,6 @@
# @TEST-EXEC: zeek -b %INPUT >output 2>&1 # @TEST-EXEC: zeek -b %INPUT >output
# @TEST-EXEC: btest-diff output # @TEST-EXEC: btest-diff output
# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff .stderr
# Demo policy for the sizeof operator "|x|". # Demo policy for the sizeof operator "|x|".
# ------------------------------------------ # ------------------------------------------