Skip to content

Commit 35d46f3

Browse files
committed
Pointer overflow checks should detect overflow in offset multiplication
Pointer arithmetic requires multiplication of the offset by the size of the base type (for any base type larger than 1 byte). Such a multiplication isn't introduced until the back-end, where no opportunity for adding properties exists anymore. Therefore, synthesize the multiplication to generate arithmetic overflow checks at the GOTO level. Fixes: diffblue#6631
1 parent 562dab9 commit 35d46f3

File tree

3 files changed

+47
-0
lines changed

3 files changed

+47
-0
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <stdint.h>
2+
3+
int main()
4+
{
5+
int32_t i[5];
6+
// Offset 1 resulted in spuriously failing to detect an overflow in pointer
7+
// arithmetic in the next line for PTRDIFF_MAX * 4 + 4 = 0 in wrap-around
8+
// semantics. Any other offset would yield the expected failure.
9+
int32_t *p = &i[1];
10+
int32_t *q = p + PTRDIFF_MAX;
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--pointer-overflow-check
4+
^\[main.overflow.1\] line 17 arithmetic overflow on signed \* in (0x)?[0-9a-fA-F]+l* \* \(signed (long (long )?)?int\)4ul*: FAILURE$
5+
^\*\* 1 of \d+ failed
6+
^VERIFICATION FAILED$
7+
^EXIT=10$
8+
^SIGNAL=0$
9+
--
10+
^warning: ignoring

src/analyses/goto_check_c.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,32 @@ void goto_check_ct::pointer_overflow_check(
13461346
expr.operands().size() == 2,
13471347
"pointer arithmetic expected to have exactly 2 operands");
13481348

1349+
// multiplying the offset by the object size must not result in arithmetic
1350+
// overflow
1351+
const typet &object_type = to_pointer_type(expr.type()).base_type();
1352+
if(object_type.id() != ID_empty)
1353+
{
1354+
auto size_of_expr_opt = size_of_expr(object_type, ns);
1355+
CHECK_RETURN(size_of_expr_opt.has_value());
1356+
exprt object_size = size_of_expr_opt.value();
1357+
1358+
const binary_exprt &binary_expr = to_binary_expr(expr);
1359+
exprt offset_operand = binary_expr.lhs().type().id() == ID_pointer
1360+
? binary_expr.rhs()
1361+
: binary_expr.lhs();
1362+
mult_exprt mul{
1363+
offset_operand,
1364+
typecast_exprt::conditional_cast(object_size, offset_operand.type())};
1365+
mul.add_source_location() = offset_operand.source_location();
1366+
1367+
flag_resett resetter(offset_operand.source_location());
1368+
resetter.set_flag(
1369+
enable_signed_overflow_check, true, "signed_overflow_check");
1370+
resetter.set_flag(
1371+
enable_unsigned_overflow_check, true, "unsigned_overflow_check");
1372+
integer_overflow_check(mul, guard);
1373+
}
1374+
13491375
// the result must be within object bounds or one past the end
13501376
const auto size = from_integer(0, size_type());
13511377
auto conditions = get_pointer_dereferenceable_conditions(expr, size);

0 commit comments

Comments
 (0)