Skip to content

Commit 419837e

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: #6631
1 parent 9719755 commit 419837e

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 10 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
@@ -1343,6 +1343,32 @@ void goto_check_ct::pointer_overflow_check(
13431343
expr.operands().size() == 2,
13441344
"pointer arithmetic expected to have exactly 2 operands");
13451345

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

0 commit comments

Comments
 (0)