Skip to content

Commit 4329b28

Browse files
authored
Merge pull request #3689 from diffblue/mod_minus_one
add check for INT_MIN % -1
2 parents 8a137fe + 53a79b6 commit 4329b28

File tree

3 files changed

+57
-6
lines changed

3 files changed

+57
-6
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <limits.h>
2+
3+
int main()
4+
{
5+
signed int x, y;
6+
7+
// this is undefined in C11
8+
y = -1;
9+
x = INT_MIN % y;
10+
11+
// always ok
12+
x = y % 2;
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
mod_overflow.c
3+
--signed-overflow-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[.*\] line 9 result of signed mod is not representable in .*: FAILURE$
7+
^VERIFICATION FAILED$
8+
--
9+
^\[.*\] line 12 result of signed mod is not representable in .*: FAILURE$
10+
^warning: ignoring

src/analyses/goto_check.cpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ class goto_checkt
105105
void bounds_check(const index_exprt &, const guardt &);
106106
void div_by_zero_check(const div_exprt &, const guardt &);
107107
void mod_by_zero_check(const mod_exprt &, const guardt &);
108+
void mod_overflow_check(const mod_exprt &, const guardt &);
108109
void undefined_shift_check(const shift_exprt &, const guardt &);
109110
void pointer_rel_check(const exprt &, const guardt &);
110111
void pointer_overflow_check(const exprt &, const guardt &);
@@ -328,7 +329,7 @@ void goto_checkt::mod_by_zero_check(
328329
const mod_exprt &expr,
329330
const guardt &guard)
330331
{
331-
if(!enable_div_by_zero_check)
332+
if(!enable_div_by_zero_check || mode == ID_java)
332333
return;
333334

334335
// add divison by zero subgoal
@@ -349,6 +350,37 @@ void goto_checkt::mod_by_zero_check(
349350
guard);
350351
}
351352

353+
/// check a mod expression for the case INT_MIN % -1
354+
void goto_checkt::mod_overflow_check(const mod_exprt &expr, const guardt &guard)
355+
{
356+
if(!enable_signed_overflow_check)
357+
return;
358+
359+
const auto &type = expr.type();
360+
361+
if(type.id() == ID_signedbv)
362+
{
363+
// INT_MIN % -1 is, in principle, defined to be zero in
364+
// ANSI C, C99, C++98, and C++11. Most compilers, however,
365+
// fail to produce 0, and in some cases generate an exception.
366+
// C11 explicitly makes this case undefined.
367+
368+
notequal_exprt int_min_neq(
369+
expr.op0(), to_signedbv_type(type).smallest_expr());
370+
371+
notequal_exprt minus_one_neq(
372+
expr.op1(), from_integer(-1, expr.op1().type()));
373+
374+
add_guarded_claim(
375+
or_exprt(int_min_neq, minus_one_neq),
376+
"result of signed mod is not representable",
377+
"overflow",
378+
expr.find_source_location(),
379+
expr,
380+
guard);
381+
}
382+
}
383+
352384
void goto_checkt::conversion_check(
353385
const exprt &expr,
354386
const guardt &guard)
@@ -564,11 +596,6 @@ void goto_checkt::integer_overflow_check(
564596

565597
return;
566598
}
567-
else if(expr.id()==ID_mod)
568-
{
569-
// these can't overflow
570-
return;
571-
}
572599
else if(expr.id()==ID_unary_minus)
573600
{
574601
if(type.id()==ID_signedbv)
@@ -1544,6 +1571,7 @@ void goto_checkt::check_rec(const exprt &expr, guardt &guard, bool address)
15441571
else if(expr.id()==ID_mod)
15451572
{
15461573
mod_by_zero_check(to_mod_expr(expr), guard);
1574+
mod_overflow_check(to_mod_expr(expr), guard);
15471575
}
15481576
else if(expr.id()==ID_plus || expr.id()==ID_minus ||
15491577
expr.id()==ID_mult ||

0 commit comments

Comments
 (0)