Skip to content

Commit

Permalink
Update documentation to clarify a GCC extension [PR77650]
Browse files Browse the repository at this point in the history
on a structure with a C99 flexible array member being nested in
another structure.

"The GCC extension accepts a structure containing an ISO C99 "flexible array
member", or a union containing such a structure (possibly recursively)
to be a member of a structure.

 There are two situations:

   * A structure containing a C99 flexible array member, or a union
     containing such a structure, is the last field of another structure,
     for example:

          struct flex  { int length; char data[]; };
          union union_flex { int others; struct flex f; };

          struct out_flex_struct { int m; struct flex flex_data; };
          struct out_flex_union { int n; union union_flex flex_data; };

     In the above, both 'out_flex_struct.flex_data.data[]' and
     'out_flex_union.flex_data.f.data[]' are considered as flexible
     arrays too.

   * A structure containing a C99 flexible array member, or a union
     containing such a structure, is not the last 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, accessing a member of the array 'mid_flex.flex_data.data[]'
     might have undefined behavior.  Compilers do not handle such a case
     consistently, Any code relying on this case should be modified to ensure
     that flexible array members only end up at the ends of structures.

     Please use the warning option '-Wflex-array-member-not-at-end' to
     identify all such cases in the source code and modify them.  This
     warning will be on by default starting from GCC 15.
"

gcc/c-family/ChangeLog:

	* c.opt: New option -Wflex-array-member-not-at-end.

gcc/c/ChangeLog:

	* c-decl.cc (finish_struct): Issue warnings for new option.

gcc/ChangeLog:

	* doc/extend.texi: Document GCC extension on a structure containing
	a flexible array member to be a member of another structure.

gcc/testsuite/ChangeLog:

	* gcc.dg/variable-sized-type-flex-array.c: New test.
  • Loading branch information
qingzhao69 authored and ouuleilei-bot committed May 25, 2023
1 parent 61957ae commit 19aef21
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 1 deletion.
5 changes: 5 additions & 0 deletions gcc/c-family/c.opt
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Wflex-array-member-not-at-end
C C++ Var(warn_flex_array_member_not_at_end) Warning
Warn when a structure containing a C99 flexible array member as the last
field is not at the end of another 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.
Expand Down
9 changes: 9 additions & 0 deletions gcc/c/c-decl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9276,6 +9276,15 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
TYPE_INCLUDES_FLEXARRAY (t)
= is_last_field && TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (x));

if (warn_flex_array_member_not_at_end
&& !is_last_field
&& RECORD_OR_UNION_TYPE_P (TREE_TYPE (x))
&& TYPE_INCLUDES_FLEXARRAY (TREE_TYPE (x)))
warning_at (DECL_SOURCE_LOCATION (x),
OPT_Wflex_array_member_not_at_end,
"structure containing a flexible array member"
" is not at the end of another structure");

if (DECL_NAME (x)
|| RECORD_OR_UNION_TYPE_P (TREE_TYPE (x)))
saw_named_field = true;
Expand Down
44 changes: 43 additions & 1 deletion gcc/doc/extend.texi
Original file line number Diff line number Diff line change
Expand Up @@ -1751,7 +1751,49 @@ 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

The GCC extension accepts a structure containing an ISO C99 @dfn{flexible array
member}, or a union containing such a structure (possibly recursively)
to be a member of a structure.

There are two situations:

@itemize @bullet
@item
A structure containing a C99 flexible array member, or a union containing
such a structure, is the last field of another structure, for example:

@smallexample
struct flex @{ int length; char data[]; @};
union union_flex @{ int others; struct flex f; @};

struct out_flex_struct @{ int m; struct flex flex_data; @};
struct out_flex_union @{ int n; union union_flex flex_data; @};
@end smallexample

In the above, both @code{out_flex_struct.flex_data.data[]} and
@code{out_flex_union.flex_data.f.data[]} are considered as flexible arrays too.

@item
A structure containing a C99 flexible array member, or a union containing
such a structure, is not the last 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, accessing a member of the array @code{mid_flex.flex_data.data[]}
might have undefined behavior. Compilers do not handle such a case
consistently. Any code relying on this case should be modified to ensure
that flexible array members only end up at the ends of structures.

Please use the warning option @option{-Wflex-array-member-not-at-end} to
identify all such cases in the source code and modify them. This warning
will be on by default starting from GCC 15.
@end itemize

Non-empty initialization of zero-length
Expand Down
31 changes: 31 additions & 0 deletions gcc/testsuite/gcc.dg/variable-sized-type-flex-array.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* Test for -Wflex-array-member-not-at-end on structure/union with
C99 flexible array members being embedded into another structure. */
/* { dg-do compile } */
/* { dg-options "-Wflex-array-member-not-at-end" } */

struct flex { int n; int data[]; };
struct out_flex_end { int m; struct flex flex_data; }; /* { dg-bogus "structure containing a flexible array member is not at the end of another structure" } */
struct out_flex_mid { struct flex flex_data; int m; }; /* { dg-warning "structure containing a flexible array member is not at the end of another structure" } */
/* 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 "structure containing a flexible array member is not at the end of another structure" } */
union flex_union_mid { int a; struct outer_flex_mid b; }; /* { dg-bogus "structure containing a flexible array member is not at the end of another structure" } */


struct flex0 { int n; int data[0]; };
struct out_flex_end0 { int m; struct flex0 flex_data; }; /* { dg-bogus "structure containing a flexible array member is not at the end of another structure" } */
struct out_flex_mid0 { struct flex0 flex_data; int m; }; /* { dg-bogus "structure containing a flexible array member is not at the end of another structure" } */
struct outer_flex_mid0 { struct out_flex_mid0 out_flex_data; int p; }; /* { dg-bogus "structure containing a flexible array member is not at the end of another structure" } */
union flex_union_mid0 { int a; struct outer_flex_mid0 b; }; /* { dg-bogus "structure containing a flexible array member is not at the end of another structure" } */

struct flex1 { int n; int data[1]; };
struct out_flex_end1 { int m; struct flex1 flex_data; }; /* { dg-bogus "structure containing a flexible array member is not at the end of another structure" } */
struct out_flex_mid1 { struct flex1 flex_data; int m; }; /* { dg-bogus "structure containing a flexible array member is not at the end of another structure" } */
struct outer_flex_mid1 { struct out_flex_mid1 out_flex_data; int p; }; /* { dg-bogus "structure containing a flexible array member is not at the end of another structure" } */
union flex_union_mid1 { int a; struct outer_flex_mid1 b; }; /* { dg-bogus "structure containing a flexible array member is not at the end of another structure" } */

struct flexn { int n; int data[8]; };
struct out_flex_endn { int m; struct flexn flex_data; }; /* { dg-bogus "structure containing a flexible array member is not at the end of another structure" } */
struct out_flex_midn { struct flexn flex_data; int m; }; /* { dg-bogus"structure containing a flexible array member is not at the end of another structure" } */
struct outer_flex_midn { struct out_flex_midn out_flex_data; int p; }; /* { dg-bogus"structure containing a flexible array member is not at the end of another structure" } */
union flex_union_midn { int a; struct outer_flex_midn b; }; /* { dg-bogus "structure containing a flexible array member is not at the end of another structure" } */

0 comments on commit 19aef21

Please sign in to comment.