forked from wangliu-iscas/gcc-patch
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR10…
…9450] Thanks Joseph! Revised version attached. Ok? But I wonder whether we generally need to do something about sizeof *x when x is NULL or not initialized. This is quite commonly used in C code and if the type is not of variable size, it is also unproblematic. So the UB for variable size is unfortunate and certainly also affects existing code in the wild. In practice it does not seem to cause problems because there is no lvalue conversion and this then seems to work. Maybe we document this as an extension? (and make sure in the C FE that it works) This would also make this idiom valid: char (*buf)[n] = malloc(sizeof *buf); Or if we do not want to do this, then I think we should add some warnings (and UBSan check for null pointer) which currently do not exist: https://godbolt.org/z/fhWMKvYc8 Martin Am Donnerstag, dem 18.05.2023 um 21:46 +0000 schrieb Joseph Myers: > On Thu, 18 May 2023, Martin Uecker via Gcc-patches wrote: > > > + /* we still have to evaluate size expressions */ > > Comments should start with a capital letter and end with ". ". > > > diff --git a/gcc/testsuite/gcc.dg/nested-vla-1.c b/gcc/testsuite/gcc.dg/nested-vla-1.c > > new file mode 100644 > > index 00000000000..408a68524d8 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/nested-vla-1.c > > @@ -0,0 +1,37 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-std=gnu99" } */ > > I'm concerned with various undefined behavior in this and other tests; > they look very fragile, relying on some optimizations and not others > taking place. I think they should be adjusted to avoid undefined behavior > if all the evaluations from the abstract machine (in particular, of sizeof > operands with variable size) take place, and other undefined behavior from > calling functions through function pointers with incompatible type. > > > + struct bar { char x[++n]; } (*bar2)(void) = bar; /* { dg-warning "incompatible pointer type" } */ > > + > > + if (2 != n) > > + __builtin_abort(); > > + > > + if (2 != sizeof((*bar2)())) > > + __builtin_abort(); > > You're relying on the compiler not noticing that a function is being > called through an incompatible type and thus not turning the call (which > should be evaluated, because the operand of sizeof has a type with > variable size) into a call to abort. > > > diff --git a/gcc/testsuite/gcc.dg/nested-vla-2.c b/gcc/testsuite/gcc.dg/nested-vla-2.c > > new file mode 100644 > > index 00000000000..504eec48c80 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/nested-vla-2.c > > @@ -0,0 +1,33 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-std=gnu99" } */ > > + > > + > > +int main() > > +{ > > + int n = 1; > > + > > + typeof(char (*)[++n]) bar(void) { } > > + > > + if (2 != n) > > + __builtin_abort(); > > + > > + if (2 != sizeof(*bar())) > > + __builtin_abort(); > > In this test, *bar() is evaluated, i.e. an undefined pointer is > dereferenced; it would be better to return a valid pointer to a > sufficiently large array to avoid that undefined behavior. > > > diff --git a/gcc/testsuite/gcc.dg/pr106465.c b/gcc/testsuite/gcc.dg/pr106465.c > > new file mode 100644 > > index 00000000000..b03e2442f12 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/pr106465.c > > @@ -0,0 +1,86 @@ > > +/* PR c/106465 > > + * { dg-do run } > > + * { dg-options "-std=gnu99" } > > + * */ > > + > > +int main() > > +{ > > + int n = 3; > > + > > + void g1(int m, struct { char p[++m]; }* b) /* { dg-warning "anonymous struct" } */ > > + { > > + if (3 != m) > > + __builtin_abort(); > > + > > + if (3 != sizeof(b->p)) > > + __builtin_abort(); > > + } > > > + g1(2, (void*)0); > > Similarly, this is dereferencing a null pointer in the evaluated operand > of sizeof. >
- Loading branch information
1 parent
c2d62cd
commit 7f6359a
Showing
26 changed files
with
566 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* { dg-do run } */ | ||
/* { dg-options "-std=gnu99" } */ | ||
|
||
|
||
int main() | ||
{ | ||
int n = 1; | ||
|
||
struct foo { char x[++n]; } bar(void) { struct foo r; return r; } | ||
|
||
if (2 != n) | ||
__builtin_abort(); | ||
|
||
if (2 != sizeof(bar())) | ||
__builtin_abort(); | ||
|
||
n = 1; | ||
|
||
struct bar { char x[++n]; } (*bar2p)(void); | ||
struct bar bar2(void) { struct bar r; return r; } | ||
bar2p = &bar2; | ||
|
||
if (2 != n) | ||
__builtin_abort(); | ||
|
||
if (2 != sizeof((*bar2p)())) | ||
__builtin_abort(); | ||
|
||
n = 1; | ||
|
||
struct str { char x[++n]; } *bar3(void) | ||
{ | ||
struct str* s = __builtin_malloc(sizeof(struct str)); | ||
if (!s) | ||
__builtin_abort(); | ||
struct str t; | ||
*s = t; | ||
return s; | ||
} | ||
|
||
if (2 != n) | ||
__builtin_abort(); | ||
|
||
struct str* p; | ||
|
||
if (2 != sizeof(*(p = bar3()))) | ||
__builtin_abort(); | ||
|
||
__builtin_free(p); | ||
|
||
n = 1; | ||
|
||
struct { char x[++n]; } *bar4(void) { } | ||
|
||
if (2 != n) | ||
__builtin_abort(); | ||
#if 0 | ||
// UB | ||
if (2 != sizeof(*bar4())) | ||
__builtin_abort(); | ||
#endif | ||
} | ||
|
Oops, something went wrong.