Skip to content

Commit 0157281

Browse files
committed
Fix type checking of ?: when one operand is void*
The C standard requires that types are compatible. For the case of void* vs. some other pointer type, GCC uses the other pointer type if, and only if, the void* operand is NULL. Fixes #134
1 parent d2bdad9 commit 0157281

File tree

6 files changed

+88
-4
lines changed

6 files changed

+88
-4
lines changed

regression/ansi-c/gcc_builtins2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33

44
^EXIT=0$
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
typedef unsigned long int uintptr_t;
2+
typedef unsigned long int uint64_t;
3+
typedef long int __intptr_t;
4+
5+
typedef struct
6+
{
7+
uintptr_t stack_guard;
8+
} tcbhead_t;
9+
10+
struct pthread
11+
{
12+
union
13+
{
14+
tcbhead_t header;
15+
};
16+
};
17+
18+
#define STATIC_ASSERT(a) int __dummy__[(a)?1:-1]
19+
20+
int main()
21+
{
22+
uintptr_t stack_chk_guard;
23+
STATIC_ASSERT(!(__builtin_classify_type ((__typeof__ (stack_chk_guard)) 0) == 5));
24+
25+
__typeof__((__typeof__ (
26+
0 ?
27+
(__typeof__ (
28+
(__typeof__ (stack_chk_guard)) 0) *) 0 :
29+
(void *) (
30+
(__builtin_classify_type (
31+
(__typeof__ (stack_chk_guard)) 0) == 5))
32+
)) 0) p1;
33+
if(*p1<0)
34+
return 0;
35+
36+
asm volatile ("movq %q0,%%fs:%P1" : :
37+
"ir" ((uint64_t) (
38+
(__typeof__ (
39+
*(0 ?
40+
(__typeof__ (
41+
0 ?
42+
(__typeof__ (
43+
(__typeof__ (stack_chk_guard)) 0) *) 0 :
44+
(void *) (
45+
(__builtin_classify_type (
46+
(__typeof__ (stack_chk_guard)) 0) == 5))
47+
)) 0 :
48+
(__typeof__ (
49+
0 ?
50+
(__intptr_t *) 0 :
51+
(void *) (
52+
!((__builtin_classify_type ((__typeof__ (stack_chk_guard)) 0) == 5))
53+
))
54+
) 0))) (stack_chk_guard))),
55+
"i" (__builtin_offsetof (struct pthread, header.stack_guard)));
56+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
8+
^CONVERSION ERROR$

src/ansi-c/c_typecast.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,9 @@ void c_typecastt::implicit_typecast_arithmetic(
794794
implicit_typecast_arithmetic(expr1, max_type);
795795
implicit_typecast_arithmetic(expr2, max_type);
796796

797+
// arithmetic typecasts only, otherwise this can't be used from
798+
// typecheck_expr_trinary
799+
#if 0
797800
if(max_type==PTR)
798801
{
799802
if(c_type1==VOIDPTR)
@@ -802,6 +805,7 @@ void c_typecastt::implicit_typecast_arithmetic(
802805
if(c_type2==VOIDPTR)
803806
do_typecast(expr2, expr1.type());
804807
}
808+
#endif
805809
}
806810

807811
/*******************************************************************\

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,10 +1762,18 @@ void c_typecheck_baset::typecheck_expr_trinary(if_exprt &expr)
17621762
operands[2].type().id()==ID_pointer &&
17631763
operands[1].type()!=operands[2].type())
17641764
{
1765-
// is one of them void *? Convert that to the other.
1766-
if(operands[1].type().subtype().id()==ID_empty)
1765+
exprt tmp1=simplify_expr(operands[1], *this);
1766+
exprt tmp2=simplify_expr(operands[2], *this);
1767+
1768+
// is one of them void * AND null? Convert that to the other.
1769+
// (at least that's how GCC behaves)
1770+
if(operands[1].type().subtype().id()==ID_empty &&
1771+
tmp1.is_constant() &&
1772+
to_constant_expr(tmp1).get_value()==ID_NULL)
17671773
implicit_typecast(operands[1], operands[2].type());
1768-
else if(operands[2].type().subtype().id()==ID_empty)
1774+
else if(operands[2].type().subtype().id()==ID_empty &&
1775+
tmp2.is_constant() &&
1776+
to_constant_expr(tmp2).get_value()==ID_NULL)
17691777
implicit_typecast(operands[2], operands[1].type());
17701778
else if(operands[1].type().subtype().id()!=ID_code ||
17711779
operands[2].type().subtype().id()!=ID_code)

src/util/simplify_expr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,14 @@ bool simplify_exprt::simplify_typecast(exprt &expr)
534534
return false;
535535
}
536536
}
537+
else if(expr_type_id==ID_pointer &&
538+
operand.is_false() &&
539+
config.ansi_c.NULL_is_zero)
540+
{
541+
expr=gen_zero(expr_type);
542+
assert(expr.is_not_nil());
543+
return false;
544+
}
537545
}
538546
else if(op_type_id==ID_unsignedbv ||
539547
op_type_id==ID_signedbv ||

0 commit comments

Comments
 (0)