Summary: | mixing ({...}) with VLA leads to massive breakage | ||
---|---|---|---|
Product: | gcc | Reporter: | Al Viro <aviro> |
Component: | c | Assignee: | Not yet assigned to anyone <unassigned> |
Status: | NEW --- | ||
Severity: | normal | CC: | egallager, gabravier, gcc-bugs, jsm-csl, msebor, muecker, pinskia, sjames, tunagul29 |
Priority: | P3 | Keywords: | ice-on-valid-code, patch, stmt-expr, wrong-code |
Version: | 4.3.0 | ||
Target Milestone: | --- | ||
URL: | https://gcc.gnu.org/pipermail/gcc-patches/2021-November/583593.html | ||
See Also: |
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=30552 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=27301 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91038 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109450 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116141 |
||
Host: | x86_64-unknown-linux-gnu | Target: | x86_64-unknown-linux-gnu |
Build: | x86_64-unknown-linux-gnu | Known to work: | |
Known to fail: | 4.3.2, 4.6.0, 5.3.0, 6.3.0, 7.0 | Last reconfirmed: | 2017-02-24 00:00:00 |
Description
Al Viro
2006-11-24 12:35:50 UTC
Subject: Re: New: mixing ({...}) with VLA leads to massive breakage This looks much the same as bug 27301, though the additional testcases are useful. 27301 looks similar to what the first one trips, but passing pointers as suggested by #3 there is not a panacea - testcases 4 and 5 actually deal with that variant. It really looks as if part (but not all) information about the type dies when we leave the scope and we end up stepping into that when working with object afterwards. testcase 2 and 3 are a front-end issue as far as I can tell: in .orginal: int n = 0; // not there for 2 which causes the ICE return (int) ((long unsigned int) SAVE_EXPR <n> * 4); Confirmed with today's top of trunk (7.0). It might be worthwhile to break up the test cases into individual bugs. $ (set -x && cat t.c && for n in 1 2 3 4 5; do gcc -DTEST=$n -O2 -S -Wall -Wextra -Wpedantic -fdump-tree-optimized=/dev/stdout t.c; done) + cat t.c #if TEST == 1 int foo(int n) // should not ICE { return ({struct {int x[n];} x; x.x[12] = 1; x;}).x[12]; } #elif TEST == 2 int foo(void) // should not ICE { return sizeof({int n = 20; struct {int x[n];} x; x.x[12] = 1; x;}); } #elif TEST == 3 int foo(void) // should not return 0 { int n = 0; return sizeof({n = 10; struct {int x[n];} x; x;}); } #elif TEST == 4 int foo(void) // should not ICE { return (*({ int n = 20; char (*x)[n][n] = __builtin_malloc(n * n); (*x)[12][1] = 1; x; }))[12][1]; } #elif TEST == 5 int foo(void) // should return 1, returns 0 { int n = 0; return (*({ n = 20; char (*x)[n][n] = __builtin_malloc(n * n); (*x)[12][1] = 1; (*x)[0][1] = 0; x; }))[12][1]; } #endif + for n in 1 2 3 4 5 + gcc -DTEST=1 -O2 -S -Wall -Wextra -Wpedantic -fdump-tree-optimized=/dev/stdout t.c t.c: In function ‘foo’: t.c:4:30: warning: a member of a structure or union cannot have a variably modified type [-Wpedantic] return ({struct {int x[n];} x; x.x[12] = 1; x;}).x[12]; ^ t.c:4:16: warning: ISO C forbids braced-groups within expressions [-Wpedantic] return ({struct {int x[n];} x; x.x[12] = 1; x;}).x[12]; ^ ;; Function foo (foo, funcdef_no=0, decl_uid=1795, cgraph_uid=0, symbol_order=0) foo (int n) { struct { int x[0:D.1807]; } * x.1; struct { int x[0:D.1807]; } * D.1814; sizetype _1; sizetype _2; int _16; <bb 2> [100.00%]: _1 = (sizetype) n_3(D); _2 = _1 * 4; _8 = __builtin_alloca_with_align (_2, 32); x.1_12 = __builtin_alloca_with_align (_2, 32); x.1_12->x[12] = 1; __builtin_memcpy (_8, x.1_12, _2); _16 = _8->x[12]; return _16; } + for n in 1 2 3 4 5 + gcc -DTEST=2 -O2 -S -Wall -Wextra -Wpedantic -fdump-tree-optimized=/dev/stdout t.c t.c: In function ‘foo’: t.c:9:48: warning: a member of a structure or union cannot have a variably modified type [-Wpedantic] return sizeof({int n = 20; struct {int x[n];} x; x.x[12] = 1; x;}); ^ t.c:9:22: warning: ISO C forbids braced-groups within expressions [-Wpedantic] return sizeof({int n = 20; struct {int x[n];} x; x.x[12] = 1; x;}); ^ t.c:9:22: internal compiler error: in gimplify_var_or_parm_decl, at gimplify.c:2582 return sizeof({int n = 20; struct {int x[n];} x; x.x[12] = 1; x;}); ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0xb93ec7 gimplify_var_or_parm_decl /ssd/src/gcc/git-svn/gcc/gimplify.c:2582 0xbba91b gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11635 0xb8d9ba internal_get_tmp_var /ssd/src/gcc/git-svn/gcc/gimplify.c:567 0xb8dd96 get_initialized_tmp_var(tree_node*, gimple**, gimple**, bool) /ssd/src/gcc/git-svn/gcc/gimplify.c:620 0xb9f95c gimplify_save_expr /ssd/src/gcc/git-svn/gcc/gimplify.c:5762 0xbb9e44 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11490 0xbb934d gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11294 0xbbb651 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11921 0xbb934d gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11294 0xb9e1dd gimplify_modify_expr /ssd/src/gcc/git-svn/gcc/gimplify.c:5457 0xbb8c6d gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11192 0xba23ca gimplify_stmt(tree_node**, gimple**) /ssd/src/gcc/git-svn/gcc/gimplify.c:6478 0xb8d545 gimplify_and_add(tree_node*, gimple**) /ssd/src/gcc/git-svn/gcc/gimplify.c:435 0xb907ab gimplify_return_expr /ssd/src/gcc/git-svn/gcc/gimplify.c:1521 0xbb9c95 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11451 0xba23ca gimplify_stmt(tree_node**, gimple**) /ssd/src/gcc/git-svn/gcc/gimplify.c:6478 0xb8fbd2 gimplify_bind_expr /ssd/src/gcc/git-svn/gcc/gimplify.c:1290 0xbb9938 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11391 0xba23ca gimplify_stmt(tree_node**, gimple**) /ssd/src/gcc/git-svn/gcc/gimplify.c:6478 0xbbcf89 gimplify_body(tree_node*, bool) /ssd/src/gcc/git-svn/gcc/gimplify.c:12388 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions. + for n in 1 2 3 4 5 + gcc -DTEST=3 -O2 -S -Wall -Wextra -Wpedantic -fdump-tree-optimized=/dev/stdout t.c t.c: In function ‘foo’: t.c:15:44: warning: a member of a structure or union cannot have a variably modified type [-Wpedantic] return sizeof({n = 10; struct {int x[n];} x; x;}); ^ t.c:15:22: warning: ISO C forbids braced-groups within expressions [-Wpedantic] return sizeof({n = 10; struct {int x[n];} x; x;}); ^ ;; Function foo (foo, funcdef_no=0, decl_uid=1795, cgraph_uid=0, symbol_order=0) foo () { <bb 2> [100.00%]: return 0; } + for n in 1 2 3 4 5 + gcc -DTEST=4 -O2 -S -Wall -Wextra -Wpedantic -fdump-tree-optimized=/dev/stdout t.c t.c: In function ‘foo’: t.c:20:18: warning: ISO C forbids braced-groups within expressions [-Wpedantic] return (*({ ^ t.c:25:24: internal compiler error: in gimplify_var_or_parm_decl, at gimplify.c:2582 return (*({ ~~~~ int n = 20; ~~~~~~~~~~~ char (*x)[n][n] = __builtin_malloc(n * n); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (*x)[12][1] = 1; ~~~~~~~~~~~~~~~~ x; ~~ }))[12][1]; ~~~~~~~^~~ 0xb93ec7 gimplify_var_or_parm_decl /ssd/src/gcc/git-svn/gcc/gimplify.c:2582 0xbba91b gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11635 0xb8d9ba internal_get_tmp_var /ssd/src/gcc/git-svn/gcc/gimplify.c:567 0xb8dd96 get_initialized_tmp_var(tree_node*, gimple**, gimple**, bool) /ssd/src/gcc/git-svn/gcc/gimplify.c:620 0xb9f95c gimplify_save_expr /ssd/src/gcc/git-svn/gcc/gimplify.c:5762 0xbb9e44 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11490 0xbb934d gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11294 0xb9484f gimplify_compound_lval /ssd/src/gcc/git-svn/gcc/gimplify.c:2799 0xbb8ad1 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11144 0xbb934d gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11294 0xb9e1dd gimplify_modify_expr /ssd/src/gcc/git-svn/gcc/gimplify.c:5457 0xbb8c6d gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11192 0xba23ca gimplify_stmt(tree_node**, gimple**) /ssd/src/gcc/git-svn/gcc/gimplify.c:6478 0xb8d545 gimplify_and_add(tree_node*, gimple**) /ssd/src/gcc/git-svn/gcc/gimplify.c:435 0xb907ab gimplify_return_expr /ssd/src/gcc/git-svn/gcc/gimplify.c:1521 0xbb9c95 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11451 0xba23ca gimplify_stmt(tree_node**, gimple**) /ssd/src/gcc/git-svn/gcc/gimplify.c:6478 0xb8fbd2 gimplify_bind_expr /ssd/src/gcc/git-svn/gcc/gimplify.c:1290 0xbb9938 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /ssd/src/gcc/git-svn/gcc/gimplify.c:11391 0xba23ca gimplify_stmt(tree_node**, gimple**) /ssd/src/gcc/git-svn/gcc/gimplify.c:6478 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions. + for n in 1 2 3 4 5 + gcc -DTEST=5 -O2 -S -Wall -Wextra -Wpedantic -fdump-tree-optimized=/dev/stdout t.c t.c: In function ‘foo’: t.c:31:18: warning: ISO C forbids braced-groups within expressions [-Wpedantic] return (*({ ^ ;; Function foo (foo, funcdef_no=0, decl_uid=1795, cgraph_uid=0, symbol_order=0) foo () { <bb 2> [100.00%]: return 0; } Related due to also mixing ({...}) with VLA: bug 30552. (Can stay separate since they're different testcases though) *** Bug 99736 has been marked as a duplicate of this bug. *** I guess i can post a workaround here This code doesnt compile: """ int main() { ({ unsigned int len = 10; struct { int array[len]; } new_object; new_object; }); } """ But this does: """ unsigned int foo(unsigned int rv) { return rv; } int main() { ({ unsigned int len = 10; struct { int array[foo(len)]; } new_object; new_object; }); } """ So according to my amateurish analysis, there seem to be at least three underlying issues: - gimplify_compound_lval size expressions are gimplified too early. This patch attempts to address this: https://gcc.gnu.org/pipermail/gcc-patches/2021-August/576484.html - inside sizeof, this seems to be a FE problem as the information from the statement expression is lost. - and then there is another issue, when a variably-sized object (but not a pointer to it) is returned from the statement expression The sizeof problem is that in c_expr_sizeof_expr the argument of sizeof is only evaluated for VLAs but not for structs of variable size. The information about the size is then lost. Changing this fixes some more cases. A third problem seems to be that in gimplify_target_expr the size expressions are also gimplified to early. Fixing this also seems to fix some of the cases, but then triggers some other down stream problems... The master branch has been updated by Martin Uecker <uecker@gcc.gnu.org>: https://gcc.gnu.org/g:0631faf87a197145acd833249bf8f20a1c4aaabf commit r12-2830-g0631faf87a197145acd833249bf8f20a1c4aaabf Author: Martin Uecker <muecker@gwdg.de> Date: Tue Aug 10 07:42:51 2021 +0200 Evaluate arguments of sizeof that are structs of variable size. Evaluate arguments of sizeof for all types of variable size and not just for VLAs. This fixes some issues related to [PR29970] where statement expressions need to be evaluated so that the size is well defined. 2021-08-10 Martin Uecker <muecker@gwdg.de> gcc/c/ PR c/29970 * c-typeck.c (c_expr_sizeof_expr): Evaluate size expressions for structs of variable size. gcc/testsuite/ PR c/29970 * gcc.dg/vla-stexp-1.c: New test. The master branch has been updated by Martin Uecker <uecker@gcc.gnu.org>: https://gcc.gnu.org/g:d2ba65ab6010f0d507bf5512a0223692e6653b23 commit r12-2882-gd2ba65ab6010f0d507bf5512a0223692e6653b23 Author: Martin Uecker <muecker@gwdg.de> Date: Thu Aug 12 20:32:16 2021 +0200 Evaluate type arguments of sizeof that are structs of variable size [PR101838] Evaluate type arguments of sizeof for all types of variable size and not just for VLAs. This fixes PR101838 and some issues related to PR29970 where statement expressions need to be evaluated so that the size is well defined. 2021-08-12 Martin Uecker <muecker@gwdg.de> gcc/c/ PR c/101838 PR c/29970 * c-typeck.c (c_expr_sizeof_type): Evaluate size expressions for structs of variable size. gcc/testsuite/ PR c/101838 * gcc.dg/vla-stexp-2.c: New test. Another version of the patch: https://gcc.gnu.org/pipermail/gcc-patches/2021-August/577402.html The remaining problem with constant index 0 for the patch mentioned above, appears to be related to fold_binary_loc which transforms (a + (x, 0)) to (x, a) which breaks if 'x' depends on something in 'a'. Another version of the patch: https://gcc.gnu.org/pipermail/gcc-patches/2021-September/578844.html Another version of the patch: https://gcc.gnu.org/pipermail/gcc-patches/2021-November/583593.html The master branch has been updated by Martin Uecker <uecker@gcc.gnu.org>: https://gcc.gnu.org/g:4e6bf0b9dd5585df1a1472d6a93b9fff72fe2524 commit r12-5338-g4e6bf0b9dd5585df1a1472d6a93b9fff72fe2524 Author: Martin Uecker <uecker@gcc.gnu.org> Date: Wed Nov 17 14:20:59 2021 +0100 Fix ICE when mixing VLAs and statement expressions [PR91038] When returning VM-types from statement expressions, this can lead to an ICE when declarations from the statement expression are referred to later. Most of these issues can be addressed by gimplifying the base expression earlier in gimplify_compound_lval. Another issue is fixed by wrapping the pointer expression in pointer_int_sum. This fixes PR91038 and some of the test cases from PR29970 (structs with VLA members need further work). gcc/ PR c/91038 PR c/29970 * gimplify.c (gimplify_var_or_parm_decl): Update comment. (gimplify_compound_lval): Gimplify base expression first. (gimplify_target_expr): Add comment. gcc/c-family/ PR c/91038 PR c/29970 * c-common.c (pointer_int_sum): Make sure pointer expressions are evaluated first when the size expression depends on for variably-modified types. gcc/testsuite/ PR c/91038 PR c/29970 * gcc.dg/vla-stexp-3.c: New test. * gcc.dg/vla-stexp-4.c: New test. * gcc.dg/vla-stexp-5.c: New test. * gcc.dg/vla-stexp-6.c: New test. * gcc.dg/vla-stexp-7.c: New test. * gcc.dg/vla-stexp-8.c: New test. * gcc.dg/vla-stexp-9.c: New test. (In reply to CVS Commits from comment #16) > The master branch has been updated by Martin Uecker <uecker@gcc.gnu.org>: > > https://gcc.gnu.org/g:4e6bf0b9dd5585df1a1472d6a93b9fff72fe2524 > > commit r12-5338-g4e6bf0b9dd5585df1a1472d6a93b9fff72fe2524 > Author: Martin Uecker <uecker@gcc.gnu.org> > Date: Wed Nov 17 14:20:59 2021 +0100 > > Fix ICE when mixing VLAs and statement expressions [PR91038] > > When returning VM-types from statement expressions, this can > lead to an ICE when declarations from the statement expression > are referred to later. Most of these issues can be addressed by > gimplifying the base expression earlier in gimplify_compound_lval. > Another issue is fixed by wrapping the pointer expression in > pointer_int_sum. This fixes PR91038 and some of the test cases > from PR29970 (structs with VLA members need further work). > > gcc/ > PR c/91038 > PR c/29970 > * gimplify.c (gimplify_var_or_parm_decl): Update comment. > (gimplify_compound_lval): Gimplify base expression first. > (gimplify_target_expr): Add comment. > > gcc/c-family/ > PR c/91038 > PR c/29970 > * c-common.c (pointer_int_sum): Make sure pointer expressions > are evaluated first when the size expression depends on for > variably-modified types. > > gcc/testsuite/ > PR c/91038 > PR c/29970 > * gcc.dg/vla-stexp-3.c: New test. > * gcc.dg/vla-stexp-4.c: New test. > * gcc.dg/vla-stexp-5.c: New test. > * gcc.dg/vla-stexp-6.c: New test. > * gcc.dg/vla-stexp-7.c: New test. > * gcc.dg/vla-stexp-8.c: New test. > * gcc.dg/vla-stexp-9.c: New test. Is this fixed now, or is it staying open for backports? What is not fixed is returning structs with VLA members as in the first three test cases, e.g. the second one still ICEs. Can also confirm this myself as I've also encountered this ICE in this code: #include <stdio.h> #define each(item, array) \ (typeof(*(array)) *foreach_p = (array), *foreach_p2 = foreach_p, (item) = {}; \ foreach_p < &((foreach_p2)[sizeof(array)/sizeof(*array)]); \ ++foreach_p)if((__builtin_memcpy(&(item), foreach_p, sizeof((item)))), 0){}else #define range1(_stop) (({ \ typeof(_stop) stop = _stop; \ struct{typeof((stop)) array[stop];}p = {}; \ if(stop < 0){ \ for(size_t i = 0; i > stop; --i) \ p.array[-i] = i; \ }else{ \ for(size_t i = 0; i < stop; ++i) \ p.array[i] = i; \ } \ p; \ }).array) int main(){ char group[][4] = { "egg", "one", "two", "moo", }; for each(x, group){ puts(x); } return sizeof(range1(6)); } which I was able to minify to: void f() { (void)({ int x = 1; struct { int array[x]; } p; p; }); } which roughly matches what testcase 2 does. |