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
> 

Reply via email to