[gcc r15-208] Allow flexible array members in unions and alone in structures [PR53548]
https://gcc.gnu.org/g:adb1c8a0f167c3a1f7593d75f5a10eb07a5d741a commit r15-208-gadb1c8a0f167c3a1f7593d75f5a10eb07a5d741a Author: Qing Zhao Date: Mon May 6 16:25:04 2024 + Allow flexible array members in unions and alone in structures [PR53548] The request for GCC to accept that the C99 flexible array member can be in a union or alone in a structure has been made a long time ago around 2012 for supporting several practical cases including glibc. A GCC PR has been opened for such request at that time: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53548 However, this PR was closed as WONTFIX around 2015 due to the following reason: "there is an existing extension that makes the requested functionality possible" i.e GCC fully supported that the zero-length array can be in a union or alone in a structure for a long time. (though I didn't see any official documentation on such extension) It's reasonable to close PR53548 at that time since zero-length array extension can be used for such purpose. However, since GCC13, in order to improve the C/C++ security, we introduced -fstrict-flex-arrays=n to gradually eliminate the "fake flexible array" usages from C/C++ source code. As a result, zero-length arrays eventually will be replaced by C99 flexiable array member completely. Therefore, GCC needs to explicitly allow such extensions directly for C99 flexible arrays, since flexable array member in unions or alone in structs are common code patterns in active use by the Linux kernel (and other projects). For example, these do not error by default with GCC: union one { int a; int b[0]; }; union two { int a; struct { struct { } __empty; int b[]; }; }; But these do: union three { int a; int b[]; }; struct four { int b[]; } Clang has supported such extensions since March, 2024 https://github.com/llvm/llvm-project/pull/84428 GCC should also support such extensions. This will allow for a seamless transition for code bases away from zero-length arrays without losing existing code patterns. gcc/ChangeLog: PR c/53548 * doc/extend.texi: Add documentation for Flexible Array Members in Unions and Flexible Array Members alone in Structures. Diff: --- gcc/doc/extend.texi | 34 ++ 1 file changed, 34 insertions(+) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index e290265d68d..267fccd1512 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -42,6 +42,8 @@ extensions, accepted by GCC in C90 mode and in C++. * Named Address Spaces::Named address spaces. * Zero Length:: Zero-length arrays. * Empty Structures::Structures with no members. +* Flexible Array Members in Unions:: Unions with Flexible Array Members. +* Flexible Array Members alone in Structures:: Structures with only Flexible Array Members. * Variable Length:: Arrays whose length is computed at run time. * Variadic Macros:: Macros with a variable number of arguments. * Escaped Newlines::Slightly looser rules for escaped newlines. @@ -1873,6 +1875,38 @@ The structure has size zero. In C++, empty structures are part of the language. G++ treats empty structures as if they had a single member of type @code{char}. +@node Flexible Array Members in Unions +@section Unions with Flexible Array Members +@cindex unions with flexible array members +@cindex unions with FAMs + +GCC permits a C99 flexible array member (FAM) to be in a union: + +@smallexample +union with_fam @{ + int a; + int b[]; +@}; +@end smallexample + +If every member of a union is a flexible array member, the size of +such a union is zero. + +@node Flexible Array Members alone in Structures +@section Structures with only Flexible Array Members +@cindex structures with only flexible array members +@cindex structures with only FAMs + +GCC permits a C99 flexible array member (FAM) to be alone in a structure: + +@smallexample +struct only_fam @{ + int b[]; +@}; +@end smallexample + +The size of such a structure is zero. + @node Variable Length @section Arrays of Variable Length @cindex variable-length arrays
[gcc r15-209] C and C++ FE changes to support flexible array members in unions and alone in structures. Adjust tes
https://gcc.gnu.org/g:f27fc59d9f7c735d200fda647a487850144b10eb commit r15-209-gf27fc59d9f7c735d200fda647a487850144b10eb Author: Qing Zhao Date: Mon May 6 16:26:19 2024 + C and C++ FE changes to support flexible array members in unions and alone in structures. Adjust testcases for flexible array member in union and alone in structure extension. PR c/53548 gcc/c/ChangeLog: PR c/53548 * c-decl.cc (finish_struct): Change errors to pedwarns for the cases flexible array members in union or alone in structures. gcc/cp/ChangeLog: PR c/53548 * class.cc (diagnose_flexarrays): Change error to pdewarn for the case flexible array members alone in structures. * decl.cc (grokdeclarator): Change error to pdewarn for the case flexible array members in unions. gcc/ChangeLog: PR c/53548 * stor-layout.cc (place_union_field): Use zero sizes for flexible array member fields. gcc/testsuite/ChangeLog: PR c/53548 * c-c++-common/builtin-clear-padding-3.c: Adjust testcase. * g++.dg/ext/flexary12.C: Likewise. * g++.dg/ext/flexary19.C: Likewise. * g++.dg/ext/flexary2.C: Likewise. * g++.dg/ext/flexary3.C: Likewise. * g++.dg/ext/flexary36.C: Likewise. * g++.dg/ext/flexary4.C: Likewise. * g++.dg/ext/flexary5.C: Likewise. * g++.dg/ext/flexary8.C: Likewise. * g++.dg/torture/pr64280.C: Likewise. * gcc.dg/20050620-1.c: Likewise. * gcc.dg/940510-1.c: Likewise. Diff: --- gcc/c/c-decl.cc| 16 ++- gcc/cp/class.cc| 11 +++-- gcc/cp/decl.cc | 7 ++- gcc/stor-layout.cc | 9 +++- .../c-c++-common/builtin-clear-padding-3.c | 10 ++-- gcc/testsuite/g++.dg/ext/flexary12.C | 6 +-- gcc/testsuite/g++.dg/ext/flexary19.C | 42 - gcc/testsuite/g++.dg/ext/flexary2.C| 2 +- gcc/testsuite/g++.dg/ext/flexary3.C| 2 +- gcc/testsuite/g++.dg/ext/flexary36.C | 2 +- gcc/testsuite/g++.dg/ext/flexary4.C| 54 +++--- gcc/testsuite/g++.dg/ext/flexary5.C| 4 +- gcc/testsuite/g++.dg/ext/flexary8.C| 8 ++-- gcc/testsuite/g++.dg/torture/pr64280.C | 2 +- gcc/testsuite/gcc.dg/20050620-1.c | 2 +- gcc/testsuite/gcc.dg/940510-1.c| 4 +- 16 files changed, 91 insertions(+), 90 deletions(-) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 52af8f32998..9ef2ab25773 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9516,11 +9516,8 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, if (flexible_array_member_type_p (TREE_TYPE (x))) { if (TREE_CODE (t) == UNION_TYPE) - { - error_at (DECL_SOURCE_LOCATION (x), - "flexible array member in union"); - TREE_TYPE (x) = error_mark_node; - } + pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic, +"flexible array member in union is a GCC extension"); else if (!is_last_field) { error_at (DECL_SOURCE_LOCATION (x), @@ -9528,12 +9525,9 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, TREE_TYPE (x) = error_mark_node; } else if (!saw_named_field) - { - error_at (DECL_SOURCE_LOCATION (x), - "flexible array member in a struct with no named " - "members"); - TREE_TYPE (x) = error_mark_node; - } + pedwarn (DECL_SOURCE_LOCATION (x), OPT_Wpedantic, +"flexible array member in a struct with no named " +"members is a GCC extension"); } if (pedantic && TREE_CODE (t) == RECORD_TYPE diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index 5ef7c71af61..0ce361eb88e 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -7624,6 +7624,7 @@ diagnose_flexarrays (tree t, const flexmems_t *fmem) bool diagd = false; const char *msg = 0; + const char *msg_fam = 0; if (TYPE_DOMAIN (TREE_TYPE (fmem->array))) { @@ -7649,15 +7650,19 @@ diagnose_flexarrays (tree t, const flexmems_t *fmem) if (fmem->after[0]) msg = G_("flexible array member %qD not at end of %q#T"); else if (!fmem->first) - msg = G_("flexible array member %qD in an otherwise empty %q#T"); + msg_fam = G_("flexible array member %qD in an otherwise" +" empty %q#T is a GCC extension"); - if (msg) + if (msg || msg_f
[gcc r15-210] Add testing cases for flexible array members in unions and alone in structures.
https://gcc.gnu.org/g:93f6a47583f3fa8a1b66856ecb19ec28f26b2ba4 commit r15-210-g93f6a47583f3fa8a1b66856ecb19ec28f26b2ba4 Author: Qing Zhao Date: Mon May 6 16:27:09 2024 + Add testing cases for flexible array members in unions and alone in structures. PR c/53548 gcc/testsuite/ChangeLog: PR c/53548 * c-c++-common/fam-in-union-alone-in-struct-1.c: New testcase. * c-c++-common/fam-in-union-alone-in-struct-2.c: New testcase. * c-c++-common/fam-in-union-alone-in-struct-3.c: New testcase. Diff: --- .../c-c++-common/fam-in-union-alone-in-struct-1.c | 52 ++ .../c-c++-common/fam-in-union-alone-in-struct-2.c | 51 + .../c-c++-common/fam-in-union-alone-in-struct-3.c | 36 +++ 3 files changed, 139 insertions(+) diff --git a/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-1.c b/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-1.c new file mode 100644 index 000..7d4721aa95a --- /dev/null +++ b/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-1.c @@ -0,0 +1,52 @@ +/* testing the correct usage of flexible array members in unions + and alone in structures. */ +/* { dg-do run} */ +/* { dg-options "-Wpedantic" } */ + +union with_fam_1 { + int a; + int b[]; /* { dg-warning "flexible array member in union is a GCC extension" } */ +}; + +union with_fam_2 { + char a; + int b[]; /* { dg-warning "flexible array member in union is a GCC extension" } */ +}; + +union with_fam_3 { + char a[]; /* { dg-warning "flexible array member in union is a GCC extension" } */ + /* { dg-warning "in an otherwise empty" "" { target c++ } .-1 } */ + int b[]; /* { dg-warning "flexible array member in union is a GCC extension" } */ +}; + +struct only_fam { + int b[]; + /* { dg-warning "in a struct with no named members" "" { target c } .-1 } */ + /* { dg-warning "in an otherwise empty" "" { target c++ } .-2 } */ + /* { dg-warning "forbids flexible array member" "" { target c++ } .-3 } */ +}; + +struct only_fam_2 { + unsigned int : 2; + unsigned int : 3; + int b[]; + /* { dg-warning "in a struct with no named members" "" { target c } .-1 } */ + /* { dg-warning "in an otherwise empty" "" { target c++ } .-2 } */ + /* { dg-warning "forbids flexible array member" "" { target c++ } .-3 } */ +}; + +int main () +{ + if (sizeof (union with_fam_1) != sizeof (int)) +__builtin_abort (); + if (sizeof (union with_fam_2) != __alignof__ (int)) +__builtin_abort (); + if (sizeof (union with_fam_3) != 0) +__builtin_abort (); + if (sizeof (struct only_fam) != 0) +__builtin_abort (); + if (sizeof (struct only_fam_2) != sizeof (int)) +__builtin_abort (); + return 0; +} + diff --git a/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-2.c b/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-2.c new file mode 100644 index 000..3743f9e7dac --- /dev/null +++ b/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-2.c @@ -0,0 +1,51 @@ +/* testing the correct usage of flexible array members in unions + and alone in structures: initialization */ +/* { dg-do run} */ +/* { dg-options "-O2" } */ + +union with_fam_1 { + int a; + int b[]; +} with_fam_1_v = {.b = {1, 2, 3, 4}}; + +union with_fam_2 { + int a; + char b[]; +} with_fam_2_v = {.a = 0x1f2f3f4f}; + +union with_fam_3 { + char a[]; + int b[]; +} with_fam_3_v = {.b = {0x1f2f3f4f, 0x5f6f7f7f}}; + +struct only_fam { + int b[]; +} only_fam_v = {{7, 11}}; + +struct only_fam_2 { + unsigned int : 2; + unsigned int : 3; + int b[]; +} only_fam_2_v = {{7, 11}}; + +int main () +{ + if (with_fam_1_v.b[3] != 4 + || with_fam_1_v.b[0] != 1) +__builtin_abort (); + if (with_fam_2_v.b[3] != 0x1f + || with_fam_2_v.b[0] != 0x4f) +__builtin_abort (); + if (with_fam_3_v.a[0] != 0x4f + || with_fam_3_v.a[7] != 0x5f) +__builtin_abort (); + if (only_fam_v.b[0] != 7 + || only_fam_v.b[1] != 11) +__builtin_abort (); + if (only_fam_2_v.b[0] != 7 + || only_fam_2_v.b[1] != 11) +__builtin_abort (); + + return 0; +} + diff --git a/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-3.c b/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-3.c new file mode 100644 index 000..dd36fa01306 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fam-in-union-alone-in-struct-3.c @@ -0,0 +1,36 @@ +/* testing the correct usage of flexible array members in unions + and alone in structures. */ +/* { dg-do compile } */ +/* { dg-options "-pedantic-errors" } */ + +union with_fam_1 { + int a; + int b[]; /* { dg-error "flexible array member in union is a GCC extension" } */ +}; + +union with_fam_2 { + char a; + int b[]; /* { dg-error "flexible array member in union is a GCC extension" } */ +}; + +union with_fam_3 { + char a[]; /* { dg-error "flexible array member in union is a GCC extension" } */ + /* { dg-error "in an otherwise empty"
[gcc r15-211] Update the C FE routine "add_flexible_array_elts_to_size" C++ FE routine "layout_var_decl" to handle
https://gcc.gnu.org/g:6634a409124a884ff66b3756568a7daae7d3c295 commit r15-211-g6634a409124a884ff66b3756568a7daae7d3c295 Author: Qing Zhao Date: Mon May 6 16:28:01 2024 + Update the C FE routine "add_flexible_array_elts_to_size" C++ FE routine "layout_var_decl" to handle the cases when the DECL is union. PR c/53548 Add testing cases to test the _bos for flexible array members in unions or alone in structures. gcc/c/ChangeLog: PR c/53548 * c-decl.cc (add_flexible_array_elts_to_size): Handle the cases when the DECL is union. gcc/cp/ChangeLog: PR c/53548 * decl.cc (layout_var_decl): Handle the cases when the DECL is union with a flexible array member initializer. gcc/testsuite/ChangeLog: PR c/53548 * c-c++-common/fam-in-union-alone-in-struct-bos-1.c: New test. * c-c++-common/fam-in-union-alone-in-struct-bos.c: New test. Diff: --- gcc/c/c-decl.cc| 29 -- gcc/cp/decl.cc | 32 --- .../fam-in-union-alone-in-struct-bos-1.c | 66 ++ .../fam-in-union-alone-in-struct-bos.c | 45 +++ 4 files changed, 159 insertions(+), 13 deletions(-) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 9ef2ab25773..b691b91b3db 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -5339,8 +5339,9 @@ zero_length_array_type_p (const_tree type) } /* INIT is a constructor that forms DECL's initializer. If the final - element initializes a flexible array field, add the size of that - initializer to DECL's size. */ + element initializes a flexible array field, adjust the size of the + DECL with the initializer based on whether the DECL is a union or + a structure. */ static void add_flexible_array_elts_to_size (tree decl, tree init) @@ -5355,10 +5356,26 @@ add_flexible_array_elts_to_size (tree decl, tree init) if (flexible_array_member_type_p (type)) { complete_array_type (&type, elt, false); - DECL_SIZE (decl) - = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type)); - DECL_SIZE_UNIT (decl) - = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), TYPE_SIZE_UNIT (type)); + /* For a structure, add the size of the initializer to the DECL's +size. */ + if (TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE) + { + DECL_SIZE (decl) + = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type)); + DECL_SIZE_UNIT (decl) + = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), + TYPE_SIZE_UNIT (type)); + } + /* For a union, the DECL's size is the maximum of the current size +and the size of the initializer. */ + else + { + DECL_SIZE (decl) + = size_binop (MAX_EXPR, DECL_SIZE (decl), TYPE_SIZE (type)); + DECL_SIZE_UNIT (decl) + = size_binop (MAX_EXPR, DECL_SIZE_UNIT (decl), + TYPE_SIZE_UNIT (type)); + } } } diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index e8622e22a4c..04a151c341c 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -6563,8 +6563,9 @@ layout_var_decl (tree decl) } } - /* If the final element initializes a flexible array field, add the size of - that initializer to DECL's size. */ + /* If the final element initializes a flexible array field, adjust + the size of the DECL with the initializer based on whether the + DECL is a union or a structure. */ if (type != error_mark_node && DECL_INITIAL (decl) && TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR @@ -6585,11 +6586,28 @@ layout_var_decl (tree decl) && TREE_CODE (vtype) == ARRAY_TYPE && COMPLETE_TYPE_P (vtype)) { - DECL_SIZE (decl) - = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (vtype)); - DECL_SIZE_UNIT (decl) - = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), - TYPE_SIZE_UNIT (vtype)); + /* For a structure, add the size of the initializer to the DECL's +size. */ + if (TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE) + { + DECL_SIZE (decl) + = size_binop (PLUS_EXPR, DECL_SIZE (decl), + TYPE_SIZE (vtype)); + DECL_SIZE_UNIT (decl) + = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), + TYPE_SIZE_UNIT (vtype)); + } + /* For a union, the DECL's size is the maximum of the current size +and the size of the initializer. */ + else + { + DECL_SIZE (decl) + = size_binop (MAX_EXPR, DECL_SIZE (
[gcc r15-3434] Explicitly document that the "counted_by" attribute is only supported in C.
https://gcc.gnu.org/g:f9642ffe7814396f31203f4366f78a43a01a215c commit r15-3434-gf9642ffe7814396f31203f4366f78a43a01a215c Author: Qing Zhao Date: Tue Sep 3 19:28:23 2024 + Explicitly document that the "counted_by" attribute is only supported in C. The "counted_by" attribute currently is only supported in C, mention this explicitly in documentation and also issue warnings when see "counted_by" attribute in C++ with -Wattributes. gcc/c-family/ChangeLog: * c-attribs.cc (handle_counted_by_attribute): Is ignored and issues warning with -Wattributes in C++ for now. gcc/ChangeLog: * doc/extend.texi: Explicitly mentions counted_by is available only in C for now. gcc/testsuite/ChangeLog: * g++.dg/ext/flex-array-counted-by.C: New test. * g++.dg/ext/flex-array-counted-by-2.C: New test. Diff: --- gcc/c-family/c-attribs.cc | 10 +- gcc/doc/extend.texi| 4 gcc/testsuite/g++.dg/ext/flex-array-counted-by-2.C | 13 + gcc/testsuite/g++.dg/ext/flex-array-counted-by.C | 11 +++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index cf27cd6d5212..79303518dcb7 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -2867,8 +2867,16 @@ handle_counted_by_attribute (tree *node, tree name, tree argval = TREE_VALUE (args); tree old_counted_by = lookup_attribute ("counted_by", DECL_ATTRIBUTES (decl)); + /* This attribute is not supported in C++. */ + if (c_dialect_cxx ()) +{ + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, + "%qE attribute is not supported for C++ for now, ignored", + name); + *no_add_attrs = true; +} /* This attribute only applies to field decls of a structure. */ - if (TREE_CODE (decl) != FIELD_DECL) + else if (TREE_CODE (decl) != FIELD_DECL) { error_at (DECL_SOURCE_LOCATION (decl), "%qE attribute is not allowed for a non-field" diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 5845bcedf6e5..ebfa6779becb 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -7926,6 +7926,10 @@ The @code{counted_by} attribute may be attached to the C99 flexible array member of a structure. It indicates that the number of the elements of the array is given by the field "@var{count}" in the same structure as the flexible array member. + +This attribute is available only in C for now. +In C++ this attribute is ignored. + GCC may use this information to improve detection of object size information for such structures and provide better results in compile-time diagnostics and runtime features like the array bound sanitizer and diff --git a/gcc/testsuite/g++.dg/ext/flex-array-counted-by-2.C b/gcc/testsuite/g++.dg/ext/flex-array-counted-by-2.C new file mode 100644 index ..6ac2b509b687 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flex-array-counted-by-2.C @@ -0,0 +1,13 @@ +/* Testing the fact that the attribute counted_by is not supported in C++. */ +/* { dg-do compile { target c++11 } } */ +/* { dg-options "-Wattributes" } */ + +struct trailing { + int count; + int field [[gnu::counted_by (count)]] []; /* { dg-warning "attribute is not supported for C\\+\\+ for now, ignored" } */ +}; + +struct trailing1 { + int count1; + [[gnu::counted_by (count)]] int field []; /* { dg-warning "attribute is not supported for C\\+\\+ for now, ignored" } */ +}; diff --git a/gcc/testsuite/g++.dg/ext/flex-array-counted-by.C b/gcc/testsuite/g++.dg/ext/flex-array-counted-by.C new file mode 100644 index ..8bc79d459dfc --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/flex-array-counted-by.C @@ -0,0 +1,11 @@ +/* Testing the fact that the attribute counted_by is not supported in C++. */ +/* { dg-do compile } */ +/* { dg-options "-Wattributes" } */ + +int size; +int x __attribute ((counted_by (size))); /* { dg-warning "attribute is not supported for C\\+\\+ for now, ignored" } */ + +struct trailing { + int count; + int field[] __attribute ((counted_by (count))); /* { dg-warning "attribute is not supported for C\\+\\+ for now, ignored" } */ +};
[gcc r13-8556] Fix SSA corruption due to widening_mul opt on conflict across an abnormal edge [PR111407]
https://gcc.gnu.org/g:2d9a9488e26233eb9497722fa9ccb88258f7402c commit r13-8556-g2d9a9488e26233eb9497722fa9ccb88258f7402c Author: Qing Zhao Date: Thu Feb 29 15:07:49 2024 + Fix SSA corruption due to widening_mul opt on conflict across an abnormal edge [PR111407] This is a bug in tree-ssa-math-opts.cc, when applying the widening mul optimization, the compiler needs to check whether the operand is in a ABNORMAL PHI, if YES, we should avoid the transformation. PR tree-optimization/111407 gcc/ChangeLog: * tree-ssa-math-opts.cc (convert_mult_to_widen): Avoid the transform when one of the operands is subject to abnormal coalescing. gcc/testsuite/ChangeLog: * gcc.dg/pr111407.c: New test. (cherry picked from commit 4aca1cfd6235090e48a53dab734437740671bbf3) Diff: --- gcc/testsuite/gcc.dg/pr111407.c | 21 + gcc/tree-ssa-math-opts.cc | 8 2 files changed, 29 insertions(+) diff --git a/gcc/testsuite/gcc.dg/pr111407.c b/gcc/testsuite/gcc.dg/pr111407.c new file mode 100644 index 000..a171074753f --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111407.c @@ -0,0 +1,21 @@ +/* PR tree-optimization/111407*/ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +enum { SEND_TOFILE } __sigsetjmp(); +void fclose(); +void foldergets(); +void sendpart_stats(int *p1, int a1, int b1) { + int *a = p1; + fclose(); + p1 = 0; + long t = b1; + if (__sigsetjmp()) { + { + long t1 = a1; + a1+=1; + fclose(a1*(long)t1); + } + } + if (p1) + fclose(); +} diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc index 15eed3e960c..ff949e4fec9 100644 --- a/gcc/tree-ssa-math-opts.cc +++ b/gcc/tree-ssa-math-opts.cc @@ -2754,6 +2754,14 @@ convert_mult_to_widen (gimple *stmt, gimple_stmt_iterator *gsi) if (!is_widening_mult_p (stmt, &type1, &rhs1, &type2, &rhs2)) return false; + /* if any one of rhs1 and rhs2 is subject to abnormal coalescing, + avoid the tranform. */ + if ((TREE_CODE (rhs1) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs1)) + || (TREE_CODE (rhs2) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs2))) +return false; + to_mode = SCALAR_INT_TYPE_MODE (type); from_mode = SCALAR_INT_TYPE_MODE (type1); if (to_mode == from_mode)
[gcc r12-10306] Fix SSA corruption due to widening_mul opt on conflict across an abnormal edge [PR111407]
https://gcc.gnu.org/g:5f23f9f141c4b52e8f4a9aadc88b8155cf1959a3 commit r12-10306-g5f23f9f141c4b52e8f4a9aadc88b8155cf1959a3 Author: Qing Zhao Date: Thu Feb 29 15:07:49 2024 + Fix SSA corruption due to widening_mul opt on conflict across an abnormal edge [PR111407] This is a bug in tree-ssa-math-opts.cc, when applying the widening mul optimization, the compiler needs to check whether the operand is in a ABNORMAL PHI, if YES, we should avoid the transformation. PR tree-optimization/111407 gcc/ChangeLog: * tree-ssa-math-opts.cc (convert_mult_to_widen): Avoid the transform when one of the operands is subject to abnormal coalescing. gcc/testsuite/ChangeLog: * gcc.dg/pr111407.c: New test. (cherry picked from commit 4aca1cfd6235090e48a53dab734437740671bbf3) Diff: --- gcc/testsuite/gcc.dg/pr111407.c | 21 + gcc/tree-ssa-math-opts.cc | 8 2 files changed, 29 insertions(+) diff --git a/gcc/testsuite/gcc.dg/pr111407.c b/gcc/testsuite/gcc.dg/pr111407.c new file mode 100644 index 000..a171074753f --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111407.c @@ -0,0 +1,21 @@ +/* PR tree-optimization/111407*/ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +enum { SEND_TOFILE } __sigsetjmp(); +void fclose(); +void foldergets(); +void sendpart_stats(int *p1, int a1, int b1) { + int *a = p1; + fclose(); + p1 = 0; + long t = b1; + if (__sigsetjmp()) { + { + long t1 = a1; + a1+=1; + fclose(a1*(long)t1); + } + } + if (p1) + fclose(); +} diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc index 232e903b0d2..bab0cc5aef4 100644 --- a/gcc/tree-ssa-math-opts.cc +++ b/gcc/tree-ssa-math-opts.cc @@ -2681,6 +2681,14 @@ convert_mult_to_widen (gimple *stmt, gimple_stmt_iterator *gsi) if (!is_widening_mult_p (stmt, &type1, &rhs1, &type2, &rhs2)) return false; + /* if any one of rhs1 and rhs2 is subject to abnormal coalescing, + avoid the tranform. */ + if ((TREE_CODE (rhs1) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs1)) + || (TREE_CODE (rhs2) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs2))) +return false; + to_mode = SCALAR_INT_TYPE_MODE (type); from_mode = SCALAR_INT_TYPE_MODE (type1); if (to_mode == from_mode)
[gcc r11-11306] Fix SSA corruption due to widening_mul opt on conflict across an abnormal edge [PR111407]
https://gcc.gnu.org/g:4de35949e462d89926a171cd1ef7b6f40a308dab commit r11-11306-g4de35949e462d89926a171cd1ef7b6f40a308dab Author: Qing Zhao Date: Mon Mar 25 14:17:56 2024 + Fix SSA corruption due to widening_mul opt on conflict across an abnormal edge [PR111407] This is a bug in tree-ssa-math-opts.c, when applying the widening mul optimization, the compiler needs to check whether the operand is in a ABNORMAL PHI, if YES, we should avoid the transformation. PR tree-optimization/111407 gcc/ChangeLog: * tree-ssa-math-opts.c (convert_mult_to_widen): Avoid the transform when one of the operands is subject to abnormal coalescing. gcc/testsuite/ChangeLog: * gcc.dg/pr111407.c: New test. (cherry picked from commit 4aca1cfd6235090e48a53dab734437740671bbf3) Diff: --- gcc/testsuite/gcc.dg/pr111407.c | 21 + gcc/tree-ssa-math-opts.c| 8 2 files changed, 29 insertions(+) diff --git a/gcc/testsuite/gcc.dg/pr111407.c b/gcc/testsuite/gcc.dg/pr111407.c new file mode 100644 index 000..a171074753f --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111407.c @@ -0,0 +1,21 @@ +/* PR tree-optimization/111407*/ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +enum { SEND_TOFILE } __sigsetjmp(); +void fclose(); +void foldergets(); +void sendpart_stats(int *p1, int a1, int b1) { + int *a = p1; + fclose(); + p1 = 0; + long t = b1; + if (__sigsetjmp()) { + { + long t1 = a1; + a1+=1; + fclose(a1*(long)t1); + } + } + if (p1) + fclose(); +} diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c index adeb70fd635..dcaf272d73f 100644 --- a/gcc/tree-ssa-math-opts.c +++ b/gcc/tree-ssa-math-opts.c @@ -2678,6 +2678,14 @@ convert_mult_to_widen (gimple *stmt, gimple_stmt_iterator *gsi) if (!is_widening_mult_p (stmt, &type1, &rhs1, &type2, &rhs2)) return false; + /* if any one of rhs1 and rhs2 is subject to abnormal coalescing, + avoid the tranform. */ + if ((TREE_CODE (rhs1) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs1)) + || (TREE_CODE (rhs2) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs2))) +return false; + to_mode = SCALAR_INT_TYPE_MODE (type); from_mode = SCALAR_INT_TYPE_MODE (type1); if (to_mode == from_mode)
[gcc r15-944] Provide counted_by attribute to flexible array member field
https://gcc.gnu.org/g:f824acd0e807546a733c122ab6340f18cef88766 commit r15-944-gf824acd0e807546a733c122ab6340f18cef88766 Author: Qing Zhao Date: Tue May 28 18:30:05 2024 + Provide counted_by attribute to flexible array member field 'counted_by (COUNT)' The 'counted_by' attribute may be attached to the C99 flexible array member of a structure. It indicates that the number of the elements of the array is given by the field "COUNT" in the same structure as the flexible array member. GCC may use this information to improve detection of object size information for such structures and provide better results in compile-time diagnostics and runtime features like the array bound sanitizer and the '__builtin_dynamic_object_size'. For instance, the following code: struct P { size_t count; char other; char array[] __attribute__ ((counted_by (count))); } *p; specifies that the 'array' is a flexible array member whose number of elements is given by the field 'count' in the same structure. The field that represents the number of the elements should have an integer type. Otherwise, the compiler reports an error and ignores the attribute. When the field that represents the number of the elements is assigned a negative integer value, the compiler treats the value as zero. An explicit 'counted_by' annotation defines a relationship between two objects, 'p->array' and 'p->count', and there are the following requirementthat on the relationship between this pair: * 'p->count' must be initialized before the first reference to 'p->array'; * 'p->array' has _at least_ 'p->count' number of elements available all the time. This relationship must hold even after any of these related objects are updated during the program. It's the user's responsibility to make sure the above requirements to be kept all the time. Otherwise the compiler reports warnings, at the same time, the results of the array bound sanitizer and the '__builtin_dynamic_object_size' is undefined. One important feature of the attribute is, a reference to the flexible array member field uses the latest value assigned to the field that represents the number of the elements before that reference. For example, p->count = val1; p->array[20] = 0; // ref1 to p->array p->count = val2; p->array[30] = 0; // ref2 to p->array in the above, 'ref1' uses 'val1' as the number of the elements in 'p->array', and 'ref2' uses 'val2' as the number of elements in 'p->array'. gcc/c-family/ChangeLog: * c-attribs.cc (handle_counted_by_attribute): New function. (attribute_takes_identifier_p): Add counted_by attribute to the list. * c-common.cc (c_flexible_array_member_type_p): ...To this. * c-common.h (c_flexible_array_member_type_p): New prototype. gcc/c/ChangeLog: * c-decl.cc (flexible_array_member_type_p): Renamed and moved to... (add_flexible_array_elts_to_size): Use renamed function. (is_flexible_array_member_p): Use renamed function. (verify_counted_by_attribute): New function. (finish_struct): Use renamed function and verify counted_by attribute. * c-tree.h (lookup_field): New prototype. * c-typeck.cc (lookup_field): Expose as extern function. (tagged_types_tu_compatible_p): Check counted_by attribute for structure type. gcc/ChangeLog: * doc/extend.texi: Document attribute counted_by. gcc/testsuite/ChangeLog: * gcc.dg/flex-array-counted-by.c: New test. * gcc.dg/flex-array-counted-by-7.c: New test. * gcc.dg/flex-array-counted-by-8.c: New test. Diff: --- gcc/c-family/c-attribs.cc | 68 - gcc/c-family/c-common.cc | 13 +++ gcc/c-family/c-common.h| 1 + gcc/c/c-decl.cc| 80 gcc/c/c-tree.h | 1 + gcc/c/c-typeck.cc | 37 ++- gcc/doc/extend.texi| 68 + gcc/testsuite/gcc.dg/flex-array-counted-by-7.c | 8 ++ gcc/testsuite/gcc.dg/flex-array-counted-by-8.c | 127 + gcc/testsuite/gcc.dg/flex-array-counted-by.c | 62 10 files changed, 444 insertions(+), 21 deletions(-) diff --git a/g
[gcc r15-945] Convert references with "counted_by" attributes to/from .ACCESS_WITH_SIZE.
https://gcc.gnu.org/g:bb49b6e4f55891d0d8b596845118f40df6ae72a5 commit r15-945-gbb49b6e4f55891d0d8b596845118f40df6ae72a5 Author: Qing Zhao Date: Tue May 28 18:34:09 2024 + Convert references with "counted_by" attributes to/from .ACCESS_WITH_SIZE. Including the following changes: * The definition of the new internal function .ACCESS_WITH_SIZE in internal-fn.def. * C FE converts every reference to a FAM with a "counted_by" attribute to a call to the internal function .ACCESS_WITH_SIZE. (build_component_ref in c_typeck.cc) This includes the case when the object is statically allocated and initialized. In order to make this working, the routine digest_init in c-typeck.cc is updated to fold calls to .ACCESS_WITH_SIZE to its first argument when require_constant is TRUE. However, for the reference inside "offsetof", the "counted_by" attribute is ignored since it's not useful at all. (c_parser_postfix_expression in c/c-parser.cc) In addtion to "offsetof", for the reference inside operator "typeof" and "alignof", we ignore counted_by attribute too. When building ADDR_EXPR for the .ACCESS_WITH_SIZE in C FE, replace the call with its first argument. * Convert every call to .ACCESS_WITH_SIZE to its first argument. (expand_ACCESS_WITH_SIZE in internal-fn.cc) * Provide the utility routines to check the call is .ACCESS_WITH_SIZE and get the reference from the call to .ACCESS_WITH_SIZE. (is_access_with_size_p and get_ref_from_access_with_size in tree.cc) gcc/c/ChangeLog: * c-parser.cc (c_parser_postfix_expression): Ignore the counted-by attribute when build_component_ref inside offsetof operator. * c-tree.h (build_component_ref): Add one more parameter. * c-typeck.cc (build_counted_by_ref): New function. (build_access_with_size_for_counted_by): New function. (build_component_ref): Check the counted-by attribute and build call to .ACCESS_WITH_SIZE. (build_unary_op): When building ADDR_EXPR for .ACCESS_WITH_SIZE, use its first argument. (lvalue_p): Accept call to .ACCESS_WITH_SIZE. (digest_init): Fold call to .ACCESS_WITH_SIZE to its first argument when require_constant is TRUE. gcc/ChangeLog: * internal-fn.cc (expand_ACCESS_WITH_SIZE): New function. * internal-fn.def (ACCESS_WITH_SIZE): New internal function. * tree.cc (is_access_with_size_p): New function. (get_ref_from_access_with_size): New function. * tree.h (is_access_with_size_p): New prototype. (get_ref_from_access_with_size): New prototype. gcc/testsuite/ChangeLog: * gcc.dg/flex-array-counted-by-2.c: New test. Diff: --- gcc/c/c-parser.cc | 10 +- gcc/c/c-tree.h | 2 +- gcc/c/c-typeck.cc | 142 - gcc/internal-fn.cc | 34 ++ gcc/internal-fn.def| 5 + gcc/testsuite/gcc.dg/flex-array-counted-by-2.c | 112 +++ gcc/tree.cc| 22 gcc/tree.h | 8 ++ 8 files changed, 328 insertions(+), 7 deletions(-) diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 00f8bf4376e..2d9e9c0969f 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -10848,9 +10848,12 @@ c_parser_postfix_expression (c_parser *parser) if (c_parser_next_token_is (parser, CPP_NAME)) { c_token *comp_tok = c_parser_peek_token (parser); + /* Ignore the counted_by attribute for reference inside + offsetof since the information is not useful at all. */ offsetof_ref = build_component_ref (loc, offsetof_ref, comp_tok->value, -comp_tok->location, UNKNOWN_LOCATION); +comp_tok->location, UNKNOWN_LOCATION, +false); c_parser_consume_token (parser); while (c_parser_next_token_is (parser, CPP_DOT) || c_parser_next_token_is (parser, @@ -10877,11 +10880,14 @@ c_parser_postfix_expression (c_parser *parser) break; } c_token *comp_tok = c_parser_peek_token (parser); + /* Ignore the counted_by attribute for reference inside + offsetof since the information is not useful. */ offsetof_ref = build_component_ref (loc, offsetof_ref,
[gcc r15-946] Use the .ACCESS_WITH_SIZE in builtin object size.
https://gcc.gnu.org/g:6f17933548fc34ee269e90546a590df8269cee60 commit r15-946-g6f17933548fc34ee269e90546a590df8269cee60 Author: Qing Zhao Date: Tue May 28 18:36:00 2024 + Use the .ACCESS_WITH_SIZE in builtin object size. gcc/ChangeLog: * tree-object-size.cc (access_with_size_object_size): New function. (call_object_size): Call the new function. gcc/testsuite/ChangeLog: * gcc.dg/builtin-object-size-common.h: Add a new macro EXPECT. * gcc.dg/flex-array-counted-by-3.c: New test. * gcc.dg/flex-array-counted-by-4.c: New test. * gcc.dg/flex-array-counted-by-5.c: New test. Diff: --- gcc/testsuite/gcc.dg/builtin-object-size-common.h | 11 ++ gcc/testsuite/gcc.dg/flex-array-counted-by-3.c| 63 gcc/testsuite/gcc.dg/flex-array-counted-by-4.c| 178 ++ gcc/testsuite/gcc.dg/flex-array-counted-by-5.c| 48 ++ gcc/tree-object-size.cc | 60 5 files changed, 360 insertions(+) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-common.h b/gcc/testsuite/gcc.dg/builtin-object-size-common.h index 66ff7cdd953..b677067c6e6 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-common.h +++ b/gcc/testsuite/gcc.dg/builtin-object-size-common.h @@ -30,3 +30,14 @@ unsigned nfails = 0; __builtin_abort ();\ return 0;\ } while (0) + +#define EXPECT(p, _v) do { \ + size_t v = _v; \ + if (p == v)\ +__builtin_printf ("ok: %s == %zd\n", #p, p);\ + else \ +{\ + __builtin_printf ("WAT: %s == %zd (expected %zd)\n", #p, p, v);\ + FAIL (); \ +}\ +} while (0); diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by-3.c b/gcc/testsuite/gcc.dg/flex-array-counted-by-3.c new file mode 100644 index 000..78f50230e89 --- /dev/null +++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-3.c @@ -0,0 +1,63 @@ +/* Test the attribute counted_by and its usage in + * __builtin_dynamic_object_size. */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#include "builtin-object-size-common.h" + +struct flex { + int b; + int c[]; +} *array_flex; + +struct annotated { + int b; + int c[] __attribute__ ((counted_by (b))); +} *array_annotated; + +struct nested_annotated { + struct { +union { + int b; + float f; +}; +int n; + }; + int c[] __attribute__ ((counted_by (b))); +} *array_nested_annotated; + +void __attribute__((__noinline__)) setup (int normal_count, int attr_count) +{ + array_flex += (struct flex *)malloc (sizeof (struct flex) ++ normal_count * sizeof (int)); + array_flex->b = normal_count; + + array_annotated += (struct annotated *)malloc (sizeof (struct annotated) + + attr_count * sizeof (int)); + array_annotated->b = attr_count; + + array_nested_annotated += (struct nested_annotated *)malloc (sizeof (struct nested_annotated) ++ attr_count * sizeof (int)); + array_nested_annotated->b = attr_count; + + return; +} + +void __attribute__((__noinline__)) test () +{ +EXPECT(__builtin_dynamic_object_size(array_flex->c, 1), -1); +EXPECT(__builtin_dynamic_object_size(array_annotated->c, 1), + array_annotated->b * sizeof (int)); +EXPECT(__builtin_dynamic_object_size(array_nested_annotated->c, 1), + array_nested_annotated->b * sizeof (int)); +} + +int main(int argc, char *argv[]) +{ + setup (10,10); + test (); + DONE (); +} diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by-4.c b/gcc/testsuite/gcc.dg/flex-array-counted-by-4.c new file mode 100644 index 000..20103d58ef5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-4.c @@ -0,0 +1,178 @@ +/* Test the attribute counted_by and its usage in +__builtin_dynamic_object_size: what's the correct behavior when the +allocation size mismatched with the value of counted_by attribute? +We should always use the latest value that is hold by the counted_by +field. */ +/* { dg-do run } */ +/* { dg-options "-O -fstrict-flex-arrays=3" } */ + +#include "builtin-object-size-common.h" + +struct annotated { + size_t foo; + char others; + char array[] __attribute__((counted_by (foo))); +}; + +#define noinline __attribute__((__noinline__)) +#define SIZE_BUMP 10 +#define MAX(a, b) ((a) > (b)
[gcc r15-947] Use the .ACCESS_WITH_SIZE in bound sanitizer.
https://gcc.gnu.org/g:3d94fee616d6132075f3292a6eafdcb7b1d3f5a5 commit r15-947-g3d94fee616d6132075f3292a6eafdcb7b1d3f5a5 Author: Qing Zhao Date: Tue May 28 18:37:14 2024 + Use the .ACCESS_WITH_SIZE in bound sanitizer. gcc/c-family/ChangeLog: * c-ubsan.cc (get_bound_from_access_with_size): New function. (ubsan_instrument_bounds): Handle call to .ACCESS_WITH_SIZE. gcc/testsuite/ChangeLog: * gcc.dg/ubsan/flex-array-counted-by-bounds-2.c: New test. * gcc.dg/ubsan/flex-array-counted-by-bounds-3.c: New test. * gcc.dg/ubsan/flex-array-counted-by-bounds-4.c: New test. * gcc.dg/ubsan/flex-array-counted-by-bounds.c: New test. Diff: --- gcc/c-family/c-ubsan.cc| 42 .../gcc.dg/ubsan/flex-array-counted-by-bounds-2.c | 45 + .../gcc.dg/ubsan/flex-array-counted-by-bounds-3.c | 34 .../gcc.dg/ubsan/flex-array-counted-by-bounds-4.c | 34 .../gcc.dg/ubsan/flex-array-counted-by-bounds.c| 46 ++ 5 files changed, 201 insertions(+) diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc index 940982819dd..7cd3c6aa5b8 100644 --- a/gcc/c-family/c-ubsan.cc +++ b/gcc/c-family/c-ubsan.cc @@ -376,6 +376,40 @@ ubsan_instrument_return (location_t loc) return build_call_expr_loc (loc, t, 1, build_fold_addr_expr_loc (loc, data)); } +/* Get the tree that represented the number of counted_by, i.e, the maximum + number of the elements of the object that the call to .ACCESS_WITH_SIZE + points to, this number will be the bound of the corresponding array. */ +static tree +get_bound_from_access_with_size (tree call) +{ + if (!is_access_with_size_p (call)) +return NULL_TREE; + + tree ref_to_size = CALL_EXPR_ARG (call, 1); + unsigned int class_of_size = TREE_INT_CST_LOW (CALL_EXPR_ARG (call, 2)); + tree type = TREE_TYPE (CALL_EXPR_ARG (call, 3)); + tree size = fold_build2 (MEM_REF, type, unshare_expr (ref_to_size), + build_int_cst (ptr_type_node, 0)); + /* If size is negative value, treat it as zero. */ + if (!TYPE_UNSIGNED (type)) + { +tree cond = fold_build2 (LT_EXPR, boolean_type_node, +unshare_expr (size), build_zero_cst (type)); +size = fold_build3 (COND_EXPR, type, cond, + build_zero_cst (type), size); + } + + /* Only when class_of_size is 1, i.e, the number of the elements of + the object type, return the size. */ + if (class_of_size != 1) +return NULL_TREE; + else +size = fold_convert (sizetype, size); + + return size; +} + + /* Instrument array bounds for ARRAY_REFs. We create special builtin, that gets expanded in the sanopt pass, and make an array dimension of it. ARRAY is the array, *INDEX is an index to the array. @@ -401,6 +435,14 @@ ubsan_instrument_bounds (location_t loc, tree array, tree *index, && COMPLETE_TYPE_P (type) && integer_zerop (TYPE_SIZE (type))) bound = build_int_cst (TREE_TYPE (TYPE_MIN_VALUE (domain)), -1); + else if (INDIRECT_REF_P (array) + && is_access_with_size_p ((TREE_OPERAND (array, 0 + { + bound = get_bound_from_access_with_size ((TREE_OPERAND (array, 0))); + bound = fold_build2 (MINUS_EXPR, TREE_TYPE (bound), + bound, + build_int_cst (TREE_TYPE (bound), 1)); + } else return NULL_TREE; } diff --git a/gcc/testsuite/gcc.dg/ubsan/flex-array-counted-by-bounds-2.c b/gcc/testsuite/gcc.dg/ubsan/flex-array-counted-by-bounds-2.c new file mode 100644 index 000..b503320628d --- /dev/null +++ b/gcc/testsuite/gcc.dg/ubsan/flex-array-counted-by-bounds-2.c @@ -0,0 +1,45 @@ +/* Test the attribute counted_by and its usage in + bounds sanitizer combined with VLA. */ +/* { dg-do run } */ +/* { dg-options "-fsanitize=bounds" } */ +/* { dg-output "index 11 out of bounds for type 'int \\\[\\\*\\\]\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*index 20 out of bounds for type 'int \\\[\\\*\\\]\\\[\\\*\\\]\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*index 11 out of bounds for type 'int \\\[\\\*\\\]\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*index 10 out of bounds for type 'int \\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */ + + +#include + +void __attribute__((__noinline__)) setup_and_test_vla (int n, int m) +{ + struct foo { + int n; + int p[][n] __attribute__((counted_by(n))); + } *f; + + f = (struct foo *) malloc (sizeof(struct foo) + m*sizeof(int[n])); + f->n = m; + f->p[m][n-1]=1; + return; +} + +void __attribute__((__noinline__)) setup_and_test_vla_1 (int n1, int n2, int m) +{ + struct foo { +int n; +int p[][n2][n1] __attribute__((counted_by(n))); + } *f; + + f = (struct foo *) malloc
[gcc r15-948] Add the 6th argument to .ACCESS_WITH_SIZE
https://gcc.gnu.org/g:4c5bea7def13613fba166edb23289bab446b0b48 commit r15-948-g4c5bea7def13613fba166edb23289bab446b0b48 Author: Qing Zhao Date: Tue May 28 18:39:31 2024 + Add the 6th argument to .ACCESS_WITH_SIZE to carry the TYPE of the flexible array. Such information is needed during tree-object-size.cc. We cannot use the result type or the type of the 1st argument of the routine .ACCESS_WITH_SIZE to decide the element type of the original array due to possible type casting in the source code. gcc/c/ChangeLog: * c-typeck.cc (build_access_with_size_for_counted_by): Add the 6th argument to .ACCESS_WITH_SIZE. gcc/ChangeLog: * tree-object-size.cc (access_with_size_object_size): Use the type of the 6th argument for the type of the element. * internal-fn.cc (expand_ACCESS_WITH_SIZE): Update the comment with the 6th argument. gcc/testsuite/ChangeLog: * gcc.dg/flex-array-counted-by-6.c: New test. Diff: --- gcc/c/c-typeck.cc | 11 -- gcc/internal-fn.cc | 2 ++ gcc/testsuite/gcc.dg/flex-array-counted-by-6.c | 46 ++ gcc/tree-object-size.cc| 16 + 4 files changed, 66 insertions(+), 9 deletions(-) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 268c3ddbe14..a0e7dbe1b48 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -2714,7 +2714,8 @@ build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) to: - (*.ACCESS_WITH_SIZE (REF, COUNTED_BY_REF, 1, (TYPE_OF_SIZE)0, -1)) + (*.ACCESS_WITH_SIZE (REF, COUNTED_BY_REF, 1, (TYPE_OF_SIZE)0, -1, + (TYPE_OF_ARRAY *)0)) NOTE: The return type of this function is the POINTER type pointing to the original flexible array type. @@ -2726,6 +2727,9 @@ build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type) The 4th argument of the call is a constant 0 with the TYPE of the object pointed by COUNTED_BY_REF. + The 6th argument of the call is a constant 0 with the pointer TYPE + to the original flexible array type. + */ static tree build_access_with_size_for_counted_by (location_t loc, tree ref, @@ -2738,12 +2742,13 @@ build_access_with_size_for_counted_by (location_t loc, tree ref, tree call = build_call_expr_internal_loc (loc, IFN_ACCESS_WITH_SIZE, - result_type, 5, + result_type, 6, array_to_pointer_conversion (loc, ref), counted_by_ref, build_int_cst (integer_type_node, 1), build_int_cst (counted_by_type, 0), - build_int_cst (integer_type_node, -1)); + build_int_cst (integer_type_node, -1), + build_int_cst (result_type, 0)); /* Wrap the call with an INDIRECT_REF with the flexible array type. */ call = build1 (INDIRECT_REF, TREE_TYPE (ref), call); SET_EXPR_LOCATION (call, loc); diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc index eb2c4cd5904..0d27f17b283 100644 --- a/gcc/internal-fn.cc +++ b/gcc/internal-fn.cc @@ -3456,6 +3456,8 @@ expand_DEFERRED_INIT (internal_fn, gcall *stmt) 1: read_only 2: write_only 3: read_write + 6th argument: A constant 0 with the pointer TYPE to the original flexible + array type. Both the return type and the type of the first argument of this function have been converted from the incomplete array type to diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by-6.c b/gcc/testsuite/gcc.dg/flex-array-counted-by-6.c new file mode 100644 index 000..65fa01443d9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-6.c @@ -0,0 +1,46 @@ +/* Test the attribute counted_by and its usage in + * __builtin_dynamic_object_size: when the type of the flexible array member + * is casting to another type. */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#include "builtin-object-size-common.h" + +typedef unsigned short u16; + +struct info { + u16 data_len; + char data[] __attribute__((counted_by(data_len))); +}; + +struct foo { + int a; + int b; +}; + +static __attribute__((__noinline__)) +struct info *setup () +{ + struct info *p; + size_t bytes = 3 * sizeof(struct foo); + + p = (struct info *)malloc (sizeof (struct info) + bytes); + p->data_len = bytes; + + return p; +} + +static void +__attribute__((__noinline__)) report (struct info *p) +{ + struct foo *bar = (struct foo *)p->data; + EXPECT(__builtin_dynamic_object_size((char *)(bar + 1), 1), 16); + EXPECT(__builtin_dynamic_object_size((char *)(bar + 2), 1), 8); +} + +int main(int argc, char *argv[]) +{ + stru
[gcc r15-4122] c: ICE in build_counted_by_ref [PR116735]
https://gcc.gnu.org/g:9a17e6d03c6ed53e3b2dfd2c3ff9b1066ffa97b9 commit r15-4122-g9a17e6d03c6ed53e3b2dfd2c3ff9b1066ffa97b9 Author: qing zhao Date: Mon Sep 30 18:29:29 2024 + c: ICE in build_counted_by_ref [PR116735] When handling the counted_by attribute, if the corresponding field doesn't exit, in additiion to issue error, we should also remove the already added non-existing "counted_by" attribute from the field_decl. PR c/116735 gcc/c/ChangeLog: * c-decl.cc (verify_counted_by_attribute): Remove the attribute when error. gcc/testsuite/ChangeLog: * gcc.dg/flex-array-counted-by-9.c: New test. Diff: --- gcc/c/c-decl.cc| 32 +++--- gcc/testsuite/gcc.dg/flex-array-counted-by-9.c | 25 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index aa7f69d1b7bc..224c015cd6df 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9502,14 +9502,17 @@ verify_counted_by_attribute (tree struct_type, tree field_decl) tree counted_by_field = lookup_field (struct_type, fieldname); - /* Error when the field is not found in the containing structure. */ + /* Error when the field is not found in the containing structure and + remove the corresponding counted_by attribute from the field_decl. */ if (!counted_by_field) -error_at (DECL_SOURCE_LOCATION (field_decl), - "argument %qE to the %qE attribute is not a field declaration" - " in the same structure as %qD", fieldname, - (get_attribute_name (attr_counted_by)), - field_decl); - +{ + error_at (DECL_SOURCE_LOCATION (field_decl), + "argument %qE to the % attribute" + " is not a field declaration in the same structure" + " as %qD", fieldname, field_decl); + DECL_ATTRIBUTES (field_decl) + = remove_attribute ("counted_by", DECL_ATTRIBUTES (field_decl)); +} else /* Error when the field is not with an integer type. */ { @@ -9518,14 +9521,15 @@ verify_counted_by_attribute (tree struct_type, tree field_decl) tree real_field = TREE_VALUE (counted_by_field); if (!INTEGRAL_TYPE_P (TREE_TYPE (real_field))) - error_at (DECL_SOURCE_LOCATION (field_decl), - "argument %qE to the %qE attribute is not a field declaration" - " with an integer type", fieldname, - (get_attribute_name (attr_counted_by))); - + { + error_at (DECL_SOURCE_LOCATION (field_decl), + "argument %qE to the % attribute" + " is not a field declaration with an integer type", + fieldname); + DECL_ATTRIBUTES (field_decl) + = remove_attribute ("counted_by", DECL_ATTRIBUTES (field_decl)); + } } - - return; } /* TYPE is a struct or union that we're applying may_alias to after the body is diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by-9.c b/gcc/testsuite/gcc.dg/flex-array-counted-by-9.c new file mode 100644 index ..5c6fedd0d3d5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-9.c @@ -0,0 +1,25 @@ +/* PR c/116735 */ +/* { dg-options "-std=c99" } */ +/* { dg-do compile } */ + +struct foo { + int len; + int element[] __attribute__ ((__counted_by__ (lenx))); /* { dg-error "attribute is not a field declaration in the same structure as" } */ +}; + +struct bar { + float count; + int array[] __attribute ((counted_by (count))); /* { dg-error "attribute is not a field declaration with an integer type" } */ +}; + +int main () +{ + struct foo *p = __builtin_malloc (sizeof (struct foo) + 3 * sizeof (int)); + struct bar *q = __builtin_malloc (sizeof (struct bar) + 3 * sizeof (int)); + p->len = 3; + p->element[0] = 17; + p->element[1] = 13; + q->array[0] = 13; + q->array[2] = 17; + return 0; +}
[gcc r13-9072] tree-optimization/116585 - SSA corruption with split_constant_offset
https://gcc.gnu.org/g:a344ba9e42224220a7279a4051a08662435b1c60 commit r13-9072-ga344ba9e42224220a7279a4051a08662435b1c60 Author: Richard Biener Date: Wed Sep 18 09:52:55 2024 +0200 tree-optimization/116585 - SSA corruption with split_constant_offset split_constant_offset when looking through SSA defs can end up picking SSA leafs that are subject to abnormal coalescing. This can lead to downstream consumers to insert code based on the result (like from dataref analysis) in places that violate constraints for abnormal coalescing. It's best to not expand defs whose operands are subject to abnormal coalescing - and not either do something when a subexpression has operands like that already. PR tree-optimization/116585 * tree-data-ref.cc (split_constant_offset_1): When either operand is subject to abnormal coalescing do no further processing. * gcc.dg/torture/pr116585.c: New testcase. (cherry picked from commit 1d0cb3b5fca69b81e69cfdb4aea0eebc1ac04750) Diff: --- gcc/testsuite/gcc.dg/torture/pr116585.c | 32 gcc/tree-data-ref.cc| 11 --- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/gcc/testsuite/gcc.dg/torture/pr116585.c b/gcc/testsuite/gcc.dg/torture/pr116585.c new file mode 100644 index ..108c481e1043 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr116585.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ + +char *s1, *s2; +extern int* my_alloc (int); +extern int _setjmp (); +extern void bar(); +void foo(int s1len, int s2len) +{ + int e; + e = _setjmp (); +{ + int l, i; + int *md = my_alloc(((sizeof(int)) * (s1len + 1) * (s2len))); + s1len++; + for (; s1len; l) + for (; s2len; l) + for (; s1len; i) + { + int j = 1; + for (; j < s2len; j++) + { + int cost; + if (s1[1] == s2[1]) + cost = 0; + else + cost = 1; + md[j * s1len ] = ((cost)); + } + } + bar(); +} +} diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc index 96934addff14..7657eeaf9e65 100644 --- a/gcc/tree-data-ref.cc +++ b/gcc/tree-data-ref.cc @@ -763,6 +763,14 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1, if (INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type)) return false; + if (TREE_CODE (op0) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op0)) +return false; + if (op1 + && TREE_CODE (op1) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op1)) +return false; + switch (code) { case INTEGER_CST: @@ -855,9 +863,6 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1, case SSA_NAME: { - if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op0)) - return false; - gimple *def_stmt = SSA_NAME_DEF_STMT (op0); enum tree_code subcode;
[gcc r14-10730] tree-optimization/116585 - SSA corruption with split_constant_offset
https://gcc.gnu.org/g:e69c03971aa50fda96b3382bfded54da3d087c32 commit r14-10730-ge69c03971aa50fda96b3382bfded54da3d087c32 Author: Richard Biener Date: Wed Sep 18 09:52:55 2024 +0200 tree-optimization/116585 - SSA corruption with split_constant_offset split_constant_offset when looking through SSA defs can end up picking SSA leafs that are subject to abnormal coalescing. This can lead to downstream consumers to insert code based on the result (like from dataref analysis) in places that violate constraints for abnormal coalescing. It's best to not expand defs whose operands are subject to abnormal coalescing - and not either do something when a subexpression has operands like that already. PR tree-optimization/116585 * tree-data-ref.cc (split_constant_offset_1): When either operand is subject to abnormal coalescing do no further processing. * gcc.dg/torture/pr116585.c: New testcase. (cherry picked from commit 1d0cb3b5fca69b81e69cfdb4aea0eebc1ac04750) Diff: --- gcc/testsuite/gcc.dg/torture/pr116585.c | 32 gcc/tree-data-ref.cc| 11 --- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/gcc/testsuite/gcc.dg/torture/pr116585.c b/gcc/testsuite/gcc.dg/torture/pr116585.c new file mode 100644 index ..108c481e1043 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr116585.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ + +char *s1, *s2; +extern int* my_alloc (int); +extern int _setjmp (); +extern void bar(); +void foo(int s1len, int s2len) +{ + int e; + e = _setjmp (); +{ + int l, i; + int *md = my_alloc(((sizeof(int)) * (s1len + 1) * (s2len))); + s1len++; + for (; s1len; l) + for (; s2len; l) + for (; s1len; i) + { + int j = 1; + for (; j < s2len; j++) + { + int cost; + if (s1[1] == s2[1]) + cost = 0; + else + cost = 1; + md[j * s1len ] = ((cost)); + } + } + bar(); +} +} diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc index 654a82202147..69b421f3c941 100644 --- a/gcc/tree-data-ref.cc +++ b/gcc/tree-data-ref.cc @@ -765,6 +765,14 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1, if (INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type)) return false; + if (TREE_CODE (op0) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op0)) +return false; + if (op1 + && TREE_CODE (op1) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op1)) +return false; + switch (code) { case INTEGER_CST: @@ -860,9 +868,6 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1, case SSA_NAME: { - if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op0)) - return false; - gimple *def_stmt = SSA_NAME_DEF_STMT (op0); enum tree_code subcode;
[gcc r12-10739] tree-optimization/116585 - SSA corruption with split_constant_offset
https://gcc.gnu.org/g:8e5bd9b4b38f5b4fbd2a95d8f61168d9eeea97d3 commit r12-10739-g8e5bd9b4b38f5b4fbd2a95d8f61168d9eeea97d3 Author: Richard Biener Date: Wed Sep 18 09:52:55 2024 +0200 tree-optimization/116585 - SSA corruption with split_constant_offset split_constant_offset when looking through SSA defs can end up picking SSA leafs that are subject to abnormal coalescing. This can lead to downstream consumers to insert code based on the result (like from dataref analysis) in places that violate constraints for abnormal coalescing. It's best to not expand defs whose operands are subject to abnormal coalescing - and not either do something when a subexpression has operands like that already. PR tree-optimization/116585 * tree-data-ref.cc (split_constant_offset_1): When either operand is subject to abnormal coalescing do no further processing. * gcc.dg/torture/pr116585.c: New testcase. (cherry picked from commit 1d0cb3b5fca69b81e69cfdb4aea0eebc1ac04750) Diff: --- gcc/testsuite/gcc.dg/torture/pr116585.c | 32 gcc/tree-data-ref.cc| 11 --- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/gcc/testsuite/gcc.dg/torture/pr116585.c b/gcc/testsuite/gcc.dg/torture/pr116585.c new file mode 100644 index ..108c481e1043 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr116585.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ + +char *s1, *s2; +extern int* my_alloc (int); +extern int _setjmp (); +extern void bar(); +void foo(int s1len, int s2len) +{ + int e; + e = _setjmp (); +{ + int l, i; + int *md = my_alloc(((sizeof(int)) * (s1len + 1) * (s2len))); + s1len++; + for (; s1len; l) + for (; s2len; l) + for (; s1len; i) + { + int j = 1; + for (; j < s2len; j++) + { + int cost; + if (s1[1] == s2[1]) + cost = 0; + else + cost = 1; + md[j * s1len ] = ((cost)); + } + } + bar(); +} +} diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc index 706a49f226ed..b7bca6a9d064 100644 --- a/gcc/tree-data-ref.cc +++ b/gcc/tree-data-ref.cc @@ -761,6 +761,14 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1, if (INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type)) return false; + if (TREE_CODE (op0) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op0)) +return false; + if (op1 + && TREE_CODE (op1) == SSA_NAME + && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op1)) +return false; + switch (code) { case INTEGER_CST: @@ -853,9 +861,6 @@ split_constant_offset_1 (tree type, tree op0, enum tree_code code, tree op1, case SSA_NAME: { - if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op0)) - return false; - gimple *def_stmt = SSA_NAME_DEF_STMT (op0); enum tree_code subcode;
[gcc r15-4370] Provide new GCC builtin __builtin_counted_by_ref [PR116016]
https://gcc.gnu.org/g:e7380688fa5917011c3fb85b5e06fb00f776a95d commit r15-4370-ge7380688fa5917011c3fb85b5e06fb00f776a95d Author: Qing Zhao Date: Tue Oct 15 17:55:22 2024 + Provide new GCC builtin __builtin_counted_by_ref [PR116016] With the addition of the 'counted_by' attribute and its wide roll-out within the Linux kernel, a use case has been found that would be very nice to have for object allocators: being able to set the counted_by counter variable without knowing its name. For example, given: struct foo { ... int counter; ... struct bar array[] __attribute__((counted_by (counter))); } *p; The existing Linux object allocators are roughly: #define MAX(A, B) (A > B) ? (A) : (B) #define alloc(P, FAM, COUNT) ({ \ __auto_type __p = &(P); \ size_t __size = MAX (sizeof(*P), __builtin_offsetof (__typeof(*P), FAM) + sizeof (*(P->FAM)) * COUNT); \ *__p = kmalloc(__size); \ }) Right now, any addition of a counted_by annotation must also include an open-coded assignment of the counter variable after the allocation: p = alloc(p, array, how_many); p->counter = how_many; In order to avoid the tedious and error-prone work of manually adding the open-coded counted-by intializations everywhere in the Linux kernel, a new GCC builtin __builtin_counted_by_ref will be very useful to be added to help the adoption of the counted-by attribute. -- Built-in Function: TYPE __builtin_counted_by_ref (PTR) The built-in function '__builtin_counted_by_ref' checks whether the array object pointed by the pointer PTR has another object associated with it that represents the number of elements in the array object through the 'counted_by' attribute (i.e. the counted-by object). If so, returns a pointer to the corresponding counted-by object. If such counted-by object does not exist, returns a null pointer. This built-in function is only available in C for now. The argument PTR must be a pointer to an array. The TYPE of the returned value is a pointer type pointing to the corresponding type of the counted-by object or a void pointer type in case of a null pointer being returned. With this new builtin, the central allocator could be updated to: #define MAX(A, B) (A > B) ? (A) : (B) #define alloc(P, FAM, COUNT) ({ \ __auto_type __p = &(P); \ __auto_type __c = (COUNT); \ size_t __size = MAX (sizeof (*(*__p)),\ __builtin_offsetof (__typeof(*(*__p)),FAM) \ + sizeof (*((*__p)->FAM)) * __c); \ if ((*__p = kmalloc(__size))) { \ __auto_type ret = __builtin_counted_by_ref((*__p)->FAM); \ *_Generic(ret, void *: &(size_t){0}, default: ret) = __c; \ } \ }) And then structs can gain the counted_by attribute without needing additional open-coded counter assignments for each struct, and unannotated structs could still use the same allocator. PR c/116016 gcc/c-family/ChangeLog: * c-common.cc: Add new __builtin_counted_by_ref. * c-common.h (enum rid): Add RID_BUILTIN_COUNTED_BY_REF. gcc/c/ChangeLog: * c-decl.cc (names_builtin_p): Add RID_BUILTIN_COUNTED_BY_REF. * c-parser.cc (has_counted_by_object): New routine. (get_counted_by_ref): New routine. (c_parser_postfix_expression): Handle New RID_BUILTIN_COUNTED_BY_REF. * c-tree.h: New routine handle_counted_by_for_component_ref. * c-typeck.cc (handle_counted_by_for_component_ref): New routine. (build_component_ref): Call the new routine. gcc/ChangeLog: * doc/extend.texi: Add documentation for __builtin_counted_by_ref. gcc/testsuite/ChangeLog: * gcc.dg/builtin-counted-by-ref-1.c: New test. * gcc.dg/builtin-counted-by-ref.c: New test. Diff: --- gcc/c-family/c-common.cc| 1 + gcc/c-family/c-common.h | 1 + gcc/c/c-decl.cc | 1 + gcc/c/c-parser.cc | 79 ++ gcc/c/c-tree.h | 1 + gcc/c/c-typeck.cc | 33 -- gcc/doc/extend.texi | 55 ++ gcc/testsuite/gcc.dg/builtin-counted-by-ref-1.c | 135 gcc/testsuite/gcc.dg/builtin-counted-by-ref.c | 61 +++ 9 files changed, 358 insertions(+), 9 deletions(-) diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index ec6a5da892dd..8ad9b99
[gcc r15-9505] c: Fully fold each parameter for call to .ACCESS_WITH_SIZE [PR119717]
https://gcc.gnu.org/g:727f330f9ac661339af1121fc5c9b67dd0d35872 commit r15-9505-g727f330f9ac661339af1121fc5c9b67dd0d35872 Author: Qing Zhao Date: Mon Apr 14 19:41:12 2025 + c: Fully fold each parameter for call to .ACCESS_WITH_SIZE [PR119717] C_MAYBE_CONST_EXPR is a C FE operator that will be removed by c_fully_fold. In c_fully_fold, it assumes that operands of function calls have already been folded. However, when we build call to .ACCESS_WITH_SIZE, all its operands are not fully folded. therefore the C FE specific operator is passed to middle-end. In order to fix this issue, fully fold the parameters before building the call to .ACCESS_WITH_SIZE. PR c/119717 gcc/c/ChangeLog: * c-typeck.cc (build_access_with_size_for_counted_by): Fully fold the parameters for call to .ACCESS_WITH_SIZE. gcc/testsuite/ChangeLog: * gcc.dg/pr119717.c: New test. Diff: --- gcc/c/c-typeck.cc | 8 ++-- gcc/testsuite/gcc.dg/pr119717.c | 24 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 3870e8a15587..55d896e02df5 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -3013,12 +3013,16 @@ build_access_with_size_for_counted_by (location_t loc, tree ref, gcc_assert (c_flexible_array_member_type_p (TREE_TYPE (ref))); /* The result type of the call is a pointer to the flexible array type. */ tree result_type = c_build_pointer_type (TREE_TYPE (ref)); + tree first_param += c_fully_fold (array_to_pointer_conversion (loc, ref), false, NULL); + tree second_param += c_fully_fold (counted_by_ref, false, NULL); tree call = build_call_expr_internal_loc (loc, IFN_ACCESS_WITH_SIZE, result_type, 6, - array_to_pointer_conversion (loc, ref), - counted_by_ref, + first_param, + second_param, build_int_cst (integer_type_node, 1), build_int_cst (counted_by_type, 0), build_int_cst (integer_type_node, -1), diff --git a/gcc/testsuite/gcc.dg/pr119717.c b/gcc/testsuite/gcc.dg/pr119717.c new file mode 100644 index ..e5eedc567b3d --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr119717.c @@ -0,0 +1,24 @@ +/* PR c/119717 */ +/* { dg-additional-options "-std=c23" } */ +/* { dg-do compile } */ + +struct annotated { + unsigned count; + [[gnu::counted_by(count)]] char array[]; +}; + +[[gnu::noinline,gnu::noipa]] +static unsigned +size_of (bool x, struct annotated *a) +{ + char *p = (x ? a : 0)->array; + return __builtin_dynamic_object_size (p, 1); +} + +int main() +{ + struct annotated *p = __builtin_malloc(sizeof *p); + p->count = 0; + __builtin_printf ("the bdos whole is %ld\n", size_of (0, p)); + return 0; +}
[gcc r16-1017] C: Flex array in the middle via type alias is not reported [PR120353]
https://gcc.gnu.org/g:f37c5f1d88c9da17f16cdb33e7c9d43e4bb5f64d commit r16-1017-gf37c5f1d88c9da17f16cdb33e7c9d43e4bb5f64d Author: Qing Zhao Date: Wed May 28 21:13:38 2025 + C: Flex array in the middle via type alias is not reported [PR120353] The root cause of the bug is: the TYPE_INCLUDES_FLEXARRAY marking of the structure type is not copied to its aliased type. The fix is to copy this marking to all the variant types of the current structure type. PR c/120353 gcc/c/ChangeLog: * c-decl.cc (finish_struct): Copy TYPE_INCLUDES_FLEXARRAY marking to all the variant types of the current structure type. gcc/testsuite/ChangeLog: * gcc.dg/pr120353.c: New test. Diff: --- gcc/c/c-decl.cc | 1 + gcc/testsuite/gcc.dg/pr120353.c | 11 +++ 2 files changed, 12 insertions(+) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index e10f9c1ea7b6..38de96e12876 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9893,6 +9893,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t); C_TYPE_VARIABLY_MODIFIED (x) = C_TYPE_VARIABLY_MODIFIED (t); C_TYPE_INCOMPLETE_VARS (x) = NULL_TREE; + TYPE_INCLUDES_FLEXARRAY (x) = TYPE_INCLUDES_FLEXARRAY (t); } /* Update type location to the one of the definition, instead of e.g. diff --git a/gcc/testsuite/gcc.dg/pr120353.c b/gcc/testsuite/gcc.dg/pr120353.c new file mode 100644 index ..6f8e4acf7f26 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr120353.c @@ -0,0 +1,11 @@ +/* PR120353: Test for -Wflex-array-member-not-at-end on structure with + typedef. */ +/* { dg-do compile } */ +/* { dg-options "-Wflex-array-member-not-at-end" } */ + +typedef struct flex flex_t; +struct flex { int n; int data[]; }; +struct out_flex_mid {flex_t flex_data; int m; }; /* { dg-warning "structure containing a flexible array member is not at the end of another structure" } */ + +typedef struct flex flex_t1; +struct out_flex_mid1 {flex_t1 flex_data1; int n; }; /* { dg-warning "structure containing a flexible array member is not at the end of another structure" } */
[gcc r16-1018] C: Flex array in union followed by a structure field is not reported [PR120354]
https://gcc.gnu.org/g:70418e6c0120cfce33ab69628602dfdadbed683a commit r16-1018-g70418e6c0120cfce33ab69628602dfdadbed683a Author: Qing Zhao Date: Thu May 29 15:59:41 2025 + C: Flex array in union followed by a structure field is not reported [PR120354] There is only one last_field for a structure type, but there might be multiple last_fields for a union type, therefore we should ORed the result of TYPE_INCLUDES_FLEXARRAY for multiple last_fields of a union type. PR c/120354 gcc/c/ChangeLog: * c-decl.cc (finish_struct): Or the results for TYPE_INCLUDES_FLEXARRAY. gcc/testsuite/ChangeLog: * gcc.dg/pr120354.c: New test. Diff: --- gcc/c/c-decl.cc | 9 ++--- gcc/testsuite/gcc.dg/pr120354.c | 33 + 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 38de96e12876..1008bcaebdc9 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9649,15 +9649,18 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, DECL_NOT_FLEXARRAY (x) = !is_flexible_array_member_p (is_last_field, x); /* Set TYPE_INCLUDES_FLEXARRAY for the context of x, t. -when x is an array and is the last field. */ +when x is an array and is the last field. +There is only one last_field for a structure type, but there might +be multiple last_fields for a union type, therefore we should ORed +the result for multiple last_fields. */ if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE) TYPE_INCLUDES_FLEXARRAY (t) - = is_last_field && c_flexible_array_member_type_p (TREE_TYPE (x)); + |= is_last_field && c_flexible_array_member_type_p (TREE_TYPE (x)); /* Recursively set TYPE_INCLUDES_FLEXARRAY for the context of x, t when x is an union or record and is the last field. */ else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) TYPE_INCLUDES_FLEXARRAY (t) - = is_last_field && TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (x)); + |= is_last_field && TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (x)); if (warn_flex_array_member_not_at_end && !is_last_field diff --git a/gcc/testsuite/gcc.dg/pr120354.c b/gcc/testsuite/gcc.dg/pr120354.c new file mode 100644 index ..6749737a1737 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr120354.c @@ -0,0 +1,33 @@ +/* PR120354: Test for -Wflex-array-member-not-at-end on union with + flexible array members. */ +/* { dg-do compile } */ +/* { dg-options "-Wflex-array-member-not-at-end" } */ + +struct P {}; +union L {}; + +union X { +int x[]; +struct P y; +}; + +struct T { +union X x; /* { dg-warning "structure containing a flexible array member is not at the end of another structure" } */ +int plug; +}; + +struct Q { +int len; +int data[]; +}; + +union Y { +struct Q q; +union L y; +}; + +struct S { +union Y y; /* { dg-warning "structure containing a flexible array member is not at the end of another structure" } */ +int plug; +}; +