Skip to content

Commit 5980b0e

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 60d3466 commit 5980b0e

File tree

3 files changed

+42
-0
lines changed

3 files changed

+42
-0
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: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
--pointer-overflow-check
4+
^\[main.pointer_arithmetic.2\] line 11 pointer arithmetic: pointer outside object bounds in p + 0x7FFFFFFFFFFFFFFFl: FAILURE$
5+
^VERIFICATION FAILED$
6+
^EXIT=10$
7+
^SIGNAL=0$
8+
--
9+
^warning: ignoring

src/analyses/goto_check_c.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,27 @@ void goto_check_ct::pointer_overflow_check(
12701270
expr.operands().size() == 2,
12711271
"pointer arithmetic expected to have exactly 2 operands");
12721272

1273+
// multiplying the offset by the object size must not result in arithmetic
1274+
// overflow
1275+
const typet &object_type = to_pointer_type(expr.type()).base_type();
1276+
if(object_type.id() != ID_empty)
1277+
{
1278+
auto size_of_expr_opt = size_of_expr(object_type, ns);
1279+
CHECK_RETURN(size_of_expr_opt.has_value());
1280+
exprt object_size = size_of_expr_opt.value();
1281+
1282+
const binary_exprt &binary_expr = to_binary_expr(expr);
1283+
exprt offset_operand = binary_expr.lhs().type().id() == ID_pointer ?
1284+
binary_expr.rhs() : binary_expr.lhs();
1285+
mult_exprt mul{offset_operand, typecast_exprt::conditional_cast(object_size, offset_operand.type())};
1286+
mul.source_location() = offset_operand.source_location();
1287+
1288+
flag_resett resetter(i);
1289+
resetter.set_flag(enable_signed_overflow_check, true, "no_enum_check");
1290+
resetter.set_flag(enable_unsigned_overflow_check, true, "no_enum_check");
1291+
integer_overflow_check(mul, guard);
1292+
}
1293+
12731294
// the result must be within object bounds or one past the end
12741295
const auto size = from_integer(0, size_type());
12751296
auto conditions = get_pointer_dereferenceable_conditions(expr, size);

0 commit comments

Comments
 (0)