Skip to content

Commit 2a0230e

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 ba15087 commit 2a0230e

File tree

4 files changed

+51
-1
lines changed

4 files changed

+51
-1
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <limits.h>
2+
#include <stdint.h>
3+
4+
int main()
5+
{
6+
int32_t i[5];
7+
// Offset 1 resulted in spuriously failing to detect an overflow in pointer
8+
// arithmetic in the next line for SSIZE_MAX * 4 + 4 = 0 in wrap-around
9+
// semantics. Any other offset would yield the expected failure.
10+
int32_t *p = &i[1];
11+
int32_t *q = p + SSIZE_MAX;
12+
}
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 11 arithmetic overflow on signed \* in 0x7F+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

regression/contracts/no_redudant_checks/test.desc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ main.c
66
^\[malloc.assertion.1\].*: SUCCESS
77
^\[malloc.assertion.2\].*: SUCCESS
88
^\[main.overflow.1\].*: SUCCESS
9+
^\[main.overflow.2\].*: SUCCESS
910
^\[main.pointer_arithmetic.1\].*: SUCCESS
1011
^\[main.pointer_arithmetic.2\].*: SUCCESS
1112
^\[main.pointer_arithmetic.3\].*: SUCCESS
@@ -17,13 +18,14 @@ main.c
1718
^\[main.pointer_arithmetic.9\].*: SUCCESS
1819
^\[main.pointer_arithmetic.10\].*: SUCCESS
1920
^\[main.pointer_arithmetic.11\].*: SUCCESS
21+
^\[main.overflow.3\].*: SUCCESS
2022
^\[main.pointer_arithmetic.12\].*: SUCCESS
2123
^\[main.pointer_arithmetic.13\].*: SUCCESS
2224
^\[main.pointer_arithmetic.14\].*: SUCCESS
2325
^\[main.pointer_arithmetic.15\].*: SUCCESS
2426
^\[main.pointer_arithmetic.16\].*: SUCCESS
2527
^\[main.pointer_arithmetic.17\].*: SUCCESS
26-
^\*\* 0 of 20 failed \(1 iterations\)
28+
^\*\* 0 of 22 failed \(1 iterations\)
2729
^VERIFICATION SUCCESSFUL$
2830
--
2931
^\[main.overflow.\d+\].*: FAILURE

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)