Skip to content

Commit 37a17ad

Browse files
authored
Merge pull request #9461 from tautschnig/pr/void-pointer-arithmetic-type
C front end: arithmetic on void * yields a void *
2 parents 107a1e5 + bb30c5a commit 37a17ad

4 files changed

Lines changed: 61 additions & 3 deletions

File tree

‎regression/cbmc/ptr_arithmetic_on_null/test.desc‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
CORE gcc-only
22
main.c
33

4-
^\[main.assertion.1\] line .* assertion \(\(char \*\)NULL\) != \(char \*\)\(void \*\)0 \+ (\(.*\))?1: SUCCESS$
5-
^\[main.assertion.2\] line .* assertion \(\(char \*\)NULL\) != \(char \*\)\(void \*\)0 - (\(.*\))?1: SUCCESS$
6-
^\[main.assertion.3\] line .* assertion \(\(char \*\)NULL\) != \(char \*\)\(void \*\)0 \+ \(.*\)offset: SUCCESS$
4+
^\[main.assertion.1\] line .* assertion \(void \*\)0 != \(void \*\)\(\(char \*\)\(void \*\)0 \+ (\(.*\))?1\): SUCCESS$
5+
^\[main.assertion.2\] line .* assertion \(void \*\)0 != \(void \*\)\(\(char \*\)\(void \*\)0 - (\(.*\))?1\): SUCCESS$
6+
^\[main.assertion.3\] line .* assertion \(void \*\)0 != \(void \*\)\(\(char \*\)\(void \*\)0 \+ \(.*\)offset\): SUCCESS$
77
^\[main.assertion.4\] line .* assertion \(char \*\)\(void \*\)0 - \(char \*\)\(void \*\)0 == (\(.*\))?0: UNKNOWN$
88
^\[main.assertion.5\] line .* assertion ptr - \(signed int \*\)\(void \*\)0 == (\(.*\))?0: FAILURE$
99
^\[main.assertion.6\] line .* assertion \(ptr - (\(.*\))?1\) \+ (\(.*\))?1 == \(\(.* \*\)NULL\): UNKNOWN$
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include <assert.h>
2+
3+
// GCC computes arithmetic on void * with a size of 1, and the result is a
4+
// void * (GCC manual, "Arithmetic on void- and Function-Pointers"). Linux
5+
// 5.10's ethtool_get_any_eeprom subtracts `useraddr + sizeof(eeprom)' from a
6+
// void *, which goto-cc rejected ("pointer subtraction over different
7+
// types"): void * + integer was typed char *.
8+
int main()
9+
{
10+
char buf[16];
11+
void *a = buf + 12, *b = buf;
12+
assert(a - (b + 8) == 4);
13+
assert((b + 8) - a == -4);
14+
assert(a - (8 + b) == 4);
15+
void *c = b;
16+
c += 4;
17+
assert(c == buf + 4);
18+
c -= 2;
19+
assert(c == buf + 2);
20+
assert(sizeof(b + 1) == sizeof(void *));
21+
assert(a - (b + 8) == 5);
22+
return 0;
23+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE gcc-only
2+
main.c
3+
4+
^\[main\.assertion\.7\] line \d+ assertion a - \(b \+ 8\) == 5: FAILURE$
5+
^\*\* 1 of \d+ failed
6+
^EXIT=10$
7+
^SIGNAL=0$
8+
--
9+
^warning: ignoring
10+
pointer subtraction over different types
11+
--
12+
The other assertions hold.

‎src/ansi-c/c_typecheck_expr.cpp‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4398,6 +4398,25 @@ void c_typecheck_baset::typecheck_arithmetic_pointer(exprt &expr)
43984398
}
43994399
}
44004400

4401+
/// GCC's arithmetic on `void *' (an extension, "Pointer Arith" in the GCC
4402+
/// manual) computes with a size of 1, and the result has the pointer's type:
4403+
/// `p + 8' for a `void *' p is a `void *'. typecheck_arithmetic_pointer
4404+
/// computes it on `char *'; cast the result \p expr of the pointer
4405+
/// arithmetic back to \p pointer_type, the type of the pointer operand. A
4406+
/// compound assignment (`p += 8') is cast by the assignment itself.
4407+
static void keep_void_pointer_type(exprt &expr, const typet &pointer_type)
4408+
{
4409+
if(
4410+
expr.id() == ID_side_effect ||
4411+
to_pointer_type(pointer_type).base_type().id() != ID_empty ||
4412+
expr.type() == pointer_type)
4413+
{
4414+
return;
4415+
}
4416+
typecast_exprt result{expr, pointer_type};
4417+
expr.swap(result);
4418+
}
4419+
44014420
void c_typecheck_baset::typecheck_expr_pointer_arithmetic(exprt &expr)
44024421
{
44034422
auto &binary_expr = to_binary_expr(expr);
@@ -4432,9 +4451,11 @@ void c_typecheck_baset::typecheck_expr_pointer_arithmetic(exprt &expr)
44324451
type1.id()==ID_c_bit_field ||
44334452
type1.id()==ID_c_enum_tag))
44344453
{
4454+
const typet pointer_type = type0;
44354455
typecheck_arithmetic_pointer(op0);
44364456
make_index_type(op1);
44374457
expr.type() = op0.type();
4458+
keep_void_pointer_type(expr, pointer_type);
44384459
return;
44394460
}
44404461
}
@@ -4468,9 +4489,11 @@ void c_typecheck_baset::typecheck_expr_pointer_arithmetic(exprt &expr)
44684489
int_op_type.id()==ID_c_bit_field ||
44694490
int_op_type.id()==ID_c_enum_tag)
44704491
{
4492+
const typet pointer_type = p_op->type();
44714493
typecheck_arithmetic_pointer(*p_op);
44724494
make_index_type(*int_op);
44734495
expr.type()=p_op->type();
4496+
keep_void_pointer_type(expr, pointer_type);
44744497
return;
44754498
}
44764499
}

0 commit comments

Comments
 (0)