Ping… Qing
> On Feb 10, 2023, at 7:50 PM, Qing Zhao <qing.z...@oracle.com> wrote: > > on structure with C99 flexible array member being nested in another structure. > > This is also fixed PR77650. > > " GCC extension accepts a structure containing a ISO C99 "flexible array > member", or a union containing such a structure (possibly recursively) > to be a member of a structure. > > There are three situations: > > * The structure with a C99 flexible array member is the last field of > another structure, for example: > > struct flex { int length; char data[]; }; > > struct out_flex { int m; struct flex flex_data; }; > > In the above, 'flex_data.data[]' is considered as a flexible array > too. > > * The structure with a C99 flexible array member is the field of > another union, for example: > > struct flex1 { int length1; char data1[]; } > struct flex2 { int length2; char data2[]; } > > union out_flex { struct flex1 flex_data1; struct flex2 flex_data2; } > > In the above, 'flex_data1.data1[]' or 'flex_data2.data2[]' is > considered as flexible arrays too. > > * The structure with a C99 flexible array member is the middle field > of another structure, for example: > > struct flex { int length; char data[]; }; > > struct mid_flex { int m; struct flex flex_data; int n; }; > > In the above, 'flex_data.data[]' is allowed to be extended flexibly > to the padding. E.g, up to 4 elements. > > However, relying on space in struct padding is a bad programming > practice, compilers do not handle such extension consistently, Any > code relying on this behavior should be modified to ensure that > flexible array members only end up at the ends of structures. > > Please use warning option '-Wgnu-variable-sized-type-not-at-end' to > identify all such cases in the source code and modify them. This > extension will be deprecated from gcc in the next release. " > > gcc/c-family/ChangeLog: > > PR c/77650 > * c.opt: New option -Wgnu-variable-sized-type-not-at-end. > > gcc/c/ChangeLog: > > PR c/77650 > * c-decl.cc (finish_struct): Issue warnings for new option. > > gcc/ChangeLog: > > PR c/77650 > * doc/extend.texi: Document GCC extension on a structure containing > a flexible array member to be a member of another structure. > > gcc/testsuite/ChangeLog: > > PR c/77650 > * gcc.dg/variable-sized-type-flex-array.c: New test. > --- > gcc/c-family/c.opt | 5 ++ > gcc/c/c-decl.cc | 7 +++ > gcc/doc/extend.texi | 58 ++++++++++++++++++- > .../gcc.dg/variable-sized-type-flex-array.c | 31 ++++++++++ > 4 files changed, 100 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/gcc.dg/variable-sized-type-flex-array.c > > diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt > index c0fea56a8f5..fd720538800 100644 > --- a/gcc/c-family/c.opt > +++ b/gcc/c-family/c.opt > @@ -737,6 +737,11 @@ Wformat-truncation= > C ObjC C++ LTO ObjC++ Joined RejectNegative UInteger Var(warn_format_trunc) > Warning LangEnabledBy(C ObjC C++ LTO ObjC++,Wformat=, warn_format >= 1, 0) > IntegerRange(0, 2) > Warn about calls to snprintf and similar functions that truncate output. > > +Wgnu-variable-sized-type-not-at-end > +C C++ Var(warn_variable_sized_type_not_at_end) Warning > +Warn about structures or unions with C99 flexible array members are not > +at the end of a structure. > + > Wif-not-aligned > C ObjC C++ ObjC++ Var(warn_if_not_aligned) Init(1) Warning > Warn when the field in a struct is not aligned. > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc > index 741a37560b0..041df4355da 100644 > --- a/gcc/c/c-decl.cc > +++ b/gcc/c/c-decl.cc > @@ -9289,6 +9289,13 @@ finish_struct (location_t loc, tree t, tree fieldlist, > tree attributes, > && is_last_field) > TYPE_INCLUDE_FLEXARRAY (t) = true; > > + if (warn_variable_sized_type_not_at_end > + && !is_last_field > + && TYPE_INCLUDE_FLEXARRAY (TREE_TYPE (x))) > + warning_at (DECL_SOURCE_LOCATION (x), > + OPT_Wgnu_variable_sized_type_not_at_end, > + "variable sized type not at the end of a struct"); > + > if (DECL_NAME (x) > || RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))) > saw_named_field = true; > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi > index 5a026c4b48c..737228b35ac 100644 > --- a/gcc/doc/extend.texi > +++ b/gcc/doc/extend.texi > @@ -1748,7 +1748,63 @@ Flexible array members may only appear as the last > member of a > A structure containing a flexible array member, or a union containing > such a structure (possibly recursively), may not be a member of a > structure or an element of an array. (However, these uses are > -permitted by GCC as extensions.) > +permitted by GCC as extensions, see details below.) > +@end itemize > + > +GCC extension accepts a structure containing a ISO C99 @dfn{flexible array > +member}, or a union containing such a structure (possibly recursively) > +to be a member of a structure. > + > +There are three situations: > + > +@itemize @bullet > +@item > +The structure with a C99 flexible array member is the last field of another > +structure, for example: > + > +@smallexample > +struct flex @{ int length; char data[]; @}; > + > +struct out_flex @{ int m; struct flex flex_data; @}; > +@end smallexample > + > +In the above, @code{flex_data.data[]} is considered as a flexible array too. > + > +@item > +The structure with a C99 flexible array member is the field of > +another union, for example: > + > +@smallexample > +struct flex1 @{ int length1; char data1[]; @} > +struct flex2 @{ int length2; char data2[]; @} > + > +union out_flex @{ struct flex1 flex_data1; struct flex2 flex_data2; @} > +@end smallexample > + > +In the above, @code{flex_data1.data1[]} or @code{flex_data2.data2[]} > +is considered as flexible arrays too. > + > +@item > +The structure with a C99 flexible array member is the middle field of another > +structure, for example: > + > +@smallexample > +struct flex @{ int length; char data[]; @}; > + > +struct mid_flex @{ int m; struct flex flex_data; int n; @}; > +@end smallexample > + > +In the above, @code{flex_data.data[]} is allowed to be extended flexibly to > +the padding. E.g, up to 4 elements. > + > +However, relying on space in struct padding is a bad programming practice, > +compilers do not handle such extension consistently, Any code relying on > +this behavior should be modified to ensure that flexible array members > +only end up at the ends of structures. > + > +Please use warning option @option{-Wgnu-variable-sized-type-not-at-end} to > +identify all such cases in the source code and modify them. This extension > +will be deprecated from gcc in the next release. > @end itemize > > Non-empty initialization of zero-length > diff --git a/gcc/testsuite/gcc.dg/variable-sized-type-flex-array.c > b/gcc/testsuite/gcc.dg/variable-sized-type-flex-array.c > new file mode 100644 > index 00000000000..e3f65c5ed07 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/variable-sized-type-flex-array.c > @@ -0,0 +1,31 @@ > +/* Test for -Wgnu-variable-sized-type-not-at-end on structure/union with > + C99 flexible array members being embedded into another structure. */ > +/* { dg-do compile } */ > +/* { dg-options "-Wgnu-variable-sized-type-not-at-end" } */ > + > +struct flex { int n; int data[]; }; > +struct out_flex_end { int m; struct flex flex_data; }; /* { dg-bogus > "variable sized type not at the end of a struct" } */ > +struct out_flex_mid { struct flex flex_data; int m; }; /* { dg-warning > "variable sized type not at the end of a struct" } */ > +/* since the warning has been issued for out_flex_mid, no need to > + issue warning again when it is included in another structure/union. */ > +struct outer_flex_mid { struct out_flex_mid out_flex_data; int p; }; /* { > dg-bogus "variable sized type not at the end of a struct" } */ > +union flex_union_mid { int a; struct outer_flex_mid b; }; /* { dg-bogus > "variable sized type not at the end of a struct" } */ > + > + > +struct flex0 { int n; int data[0]; }; > +struct out_flex_end0 { int m; struct flex0 flex_data; }; /* { dg-bogus > "variable sized type not at the end of a struct" } */ > +struct out_flex_mid0 { struct flex0 flex_data; int m; }; /* { dg-bogus > "variable sized type not at the end of a struct" } */ > +struct outer_flex_mid0 { struct out_flex_mid0 out_flex_data; int p; }; /* { > dg-bogus "variable sized type not at the end of a struct" } */ > +union flex_union_mid0 { int a; struct outer_flex_mid0 b; }; /* { dg-bogus > "variable sized type not at the end of a struct" } */ > + > +struct flex1 { int n; int data[1]; }; > +struct out_flex_end1 { int m; struct flex1 flex_data; }; /* { dg-bogus > "variable sized type not at the end of a struct" } */ > +struct out_flex_mid1 { struct flex1 flex_data; int m; }; /* { dg-bogus > "variable sized type not at the end of a struct" } */ > +struct outer_flex_mid1 { struct out_flex_mid1 out_flex_data; int p; }; /* { > dg-bogus "variable sized type not at the end of a struct" } */ > +union flex_union_mid1 { int a; struct outer_flex_mid1 b; }; /* { dg-bogus > "variable sized type not at the end of a struct" } */ > + > +struct flexn { int n; int data[8]; }; > +struct out_flex_endn { int m; struct flexn flex_data; }; /* { dg-bogus > "variable sized type not at the end of a struct" } */ > +struct out_flex_midn { struct flexn flex_data; int m; }; /* { > dg-bogus"variable sized type not at the end of a struct" } */ > +struct outer_flex_midn { struct out_flex_midn out_flex_data; int p; }; /* { > dg-bogus"variable sized type not at the end of a struct" } */ > +union flex_union_midn { int a; struct outer_flex_midn b; }; /* { dg-bogus > "variable sized type not at the end of a struct" } */ > -- > 2.31.1 >