From: Qing Zhao <qing.zhao@oracle.com>
To: Richard Biener <rguenther@suse.de>,
"joseph@codesourcery.com" <joseph@codesourcery.com>
Cc: gcc Patches <gcc-patches@gcc.gnu.org>
Subject: Re: [V2][PATCH 1/1] Add a new warning option -Wstrict-flex-arrays.
Date: Tue, 6 Dec 2022 16:16:41 +0000 [thread overview]
Message-ID: <FCBB5262-0DD4-4F87-8B31-FCECF57B7C6B@oracle.com> (raw)
In-Reply-To: <20221206161438.2396168-2-qing.zhao@oracle.com>
Sorry, Please ignore this email.
Qing
> On Dec 6, 2022, at 11:14 AM, Qing Zhao <qing.zhao@oracle.com> wrote:
>
> '-Wstrict-flex-arrays'
> Warn about inproper usages of flexible array members according to
> the LEVEL of the 'strict_flex_array (LEVEL)' attribute attached to
> the trailing array field of a structure if it's available,
> otherwise according to the LEVEL of the option
> '-fstrict-flex-arrays=LEVEL'.
>
> This option is effective only when LEVEL is bigger than 0.
> Otherwise, it will be ignored with a warning.
>
> when LEVEL=1, warnings will be issued for a trailing array
> reference of a structure that have 2 or more elements if the
> trailing array is referenced as a flexible array member.
>
> when LEVEL=2, in addition to LEVEL=1, additional warnings will be
> issued for a trailing one-element array reference of a structure if
> the array is referenced as a flexible array member.
>
> when LEVEL=3, in addition to LEVEL=2, additional warnings will be
> issued for a trailing zero-length array reference of a structure if
> the array is referenced as a flexible array member.
>
> At the same time, -Warray-bounds is updated:
>
> A. add the following to clarify the relationship with the LEVEL of
> -fstrict-flex-array:
>
> By default, the trailing array of a structure will be treated as a
> flexible array member by '-Warray-bounds' or '-Warray-bounds=N' if
> it is declared as either a flexible array member per C99 standard
> onwards ('[]'), a GCC zero-length array extension ('[0]'), or an
> one-element array ('[1]'). As a result, out of bounds subscripts
> or offsets into zero-length arrays or one-element arrays are not
> warned by default.
>
> You can add the option '-fstrict-flex-arrays' or
> '-fstrict-flex-arrays=LEVEL' to control how this option treat
> trailing array of a structure as a flexible array member.
>
> when LEVEL<=1, no change to the default behavior.
>
> when LEVEL=2, additional warnings will be issued for out of bounds
> subscripts or offsets into one-element arrays;
>
> when LEVEL=3, in addition to LEVEL=2, additional warnings will be
> issued for out of bounds subscripts or offsets into zero-length
> arrays.
>
> B. change the -Warray-bounds=2 to exclude the control on how to treat
> trailing arrays as flexible array members:
>
> '-Warray-bounds=2'
> This warning level also warns about the intermediate results
> of pointer arithmetic that may yield out of bounds values.
> This warning level may give a larger number of false positives
> and is deactivated by default.
>
> gcc/ChangeLog:
>
> * attribs.cc (strict_flex_array_level_of): New function.
> * attribs.h (strict_flex_array_level_of): Prototype for new function.
> * doc/invoke.texi: Document -Wstrict-flex-arrays option. Update
> -Warray-bounds by specifying the impact from -fstrict-flex-arrays.
> Also update -Warray-bounds=2 by eliminating its impact on treating
> trailing arrays as flexible array members.
> * gimple-array-bounds.cc (array_bounds_checker::check_array_ref):
> Issue warnings for -Wstrict-flex-arrays.
> (get_up_bounds_for_array_ref): New function.
> (check_out_of_bounds_and_warn): New function.
> * opts.cc (finish_options): Issue warning for unsupported combination
> of -Wstrict_flex_arrays and -fstrict-flex-array.
> * tree-vrp.cc (execute_ranger_vrp): Enable the pass when
> warn_strict_flex_array is true.
> * tree.cc (array_ref_flexible_size_p): Add one new argument.
> (component_ref_sam_type): New function.
> (component_ref_size): Control with level of strict-flex-array.
> * tree.h (array_ref_flexible_size_p): Update prototype.
> (enum struct special_array_member): Add two new enum values.
> (component_ref_sam_type): New prototype.
>
> gcc/c-family/ChangeLog:
>
> * c.opt (Wstrict-flex-arrays): New option.
>
> gcc/c/ChangeLog:
>
> * c-decl.cc (is_flexible_array_member_p): Call new function
> strict_flex_array_level_of.
>
> gcc/testsuite/ChangeLog:
>
> * c-c++-common/Wstrict-flex-arrays.c: New test.
> * c-c++-common/Wstrict-flex-arrays_2.c: New test.
> * gcc.dg/Warray-bounds-11.c: Update warnings for -Warray-bounds=2.
> * gcc.dg/Wstrict-flex-arrays-2.c: New test.
> * gcc.dg/Wstrict-flex-arrays-3.c: New test.
> * gcc.dg/Wstrict-flex-arrays-4.c: New test.
> * gcc.dg/Wstrict-flex-arrays-5.c: New test.
> * gcc.dg/Wstrict-flex-arrays-6.c: New test.
> * gcc.dg/Wstrict-flex-arrays-7.c: New test.
> * gcc.dg/Wstrict-flex-arrays-8.c: New test.
> * gcc.dg/Wstrict-flex-arrays-9.c: New test.
> * gcc.dg/Wstrict-flex-arrays.c: New test.
> ---
> gcc/attribs.cc | 30 +++
> gcc/attribs.h | 2 +
> gcc/c-family/c.opt | 5 +
> gcc/c/c-decl.cc | 22 +-
> gcc/doc/invoke.texi | 54 +++-
> gcc/gimple-array-bounds.cc | 240 +++++++++++++-----
> gcc/opts.cc | 8 +
> .../c-c++-common/Wstrict-flex-arrays.c | 9 +
> gcc/testsuite/gcc.dg/Warray-bounds-11.c | 2 +-
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c | 46 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c | 46 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c | 47 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c | 49 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c | 49 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c | 48 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c | 48 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c | 49 ++++
> gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c | 46 ++++
> gcc/tree-vrp.cc | 2 +-
> gcc/tree.cc | 159 +++++++++---
> gcc/tree.h | 12 +-
> 21 files changed, 833 insertions(+), 140 deletions(-)
> create mode 100644 gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
> create mode 100644 gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
>
> diff --git a/gcc/attribs.cc b/gcc/attribs.cc
> index 27dea748561..095def4d6b0 100644
> --- a/gcc/attribs.cc
> +++ b/gcc/attribs.cc
> @@ -2456,6 +2456,36 @@ init_attr_rdwr_indices (rdwr_map *rwm, tree attrs)
> }
> }
>
> +/* Get the LEVEL of the strict_flex_array for the ARRAY_FIELD based on the
> + values of attribute strict_flex_array and the flag_strict_flex_arrays. */
> +unsigned int
> +strict_flex_array_level_of (tree array_field)
> +{
> + gcc_assert (TREE_CODE (array_field) == FIELD_DECL);
> + unsigned int strict_flex_array_level = flag_strict_flex_arrays;
> +
> + tree attr_strict_flex_array
> + = lookup_attribute ("strict_flex_array", DECL_ATTRIBUTES (array_field));
> + /* If there is a strict_flex_array attribute attached to the field,
> + override the flag_strict_flex_arrays. */
> + if (attr_strict_flex_array)
> + {
> + /* Get the value of the level first from the attribute. */
> + unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
> + gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
> + attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
> + gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
> + attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
> + gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
> + attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
> +
> + /* The attribute has higher priority than flag_struct_flex_array. */
> + strict_flex_array_level = attr_strict_flex_array_level;
> + }
> + return strict_flex_array_level;
> +}
> +
> +
> /* Return the access specification for a function parameter PARM
> or null if the current function has no such specification. */
>
> diff --git a/gcc/attribs.h b/gcc/attribs.h
> index 1dc16e4bc4e..742811e6fda 100644
> --- a/gcc/attribs.h
> +++ b/gcc/attribs.h
> @@ -398,4 +398,6 @@ extern void init_attr_rdwr_indices (rdwr_map *, tree);
> extern attr_access *get_parm_access (rdwr_map &, tree,
> tree = current_function_decl);
>
> +extern unsigned int strict_flex_array_level_of (tree);
> +
> #endif // GCC_ATTRIBS_H
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 0d0ad0a6374..33edeefd285 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -976,6 +976,11 @@ Wstringop-truncation
> C ObjC C++ LTO ObjC++ Var(warn_stringop_truncation) Warning Init (1) LangEnabledBy(C ObjC C++ LTO ObjC++, Wall)
> Warn about truncation in string manipulation functions like strncat and strncpy.
>
> +Wstrict-flex-arrays
> +C C++ Var(warn_strict_flex_arrays) Warning
> +Warn about inproper usages of flexible array members
> +according to the level of -fstrict-flex-arrays.
> +
> Wsuggest-attribute=format
> C ObjC C++ ObjC++ Var(warn_suggest_attribute_format) Warning
> Warn about functions which might be candidates for format attributes.
> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> index 4adb89e4aaf..f8cfb1d1090 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -9040,7 +9040,6 @@ finish_incomplete_vars (tree incomplete_vars, bool toplevel)
> }
> }
>
> -
> /* Determine whether the FIELD_DECL X is a flexible array member according to
> the following info:
> A. whether the FIELD_DECL X is the last field of the DECL_CONTEXT;
> @@ -9067,26 +9066,7 @@ is_flexible_array_member_p (bool is_last_field,
> bool is_one_element_array = one_element_array_type_p (TREE_TYPE (x));
> bool is_flexible_array = flexible_array_member_type_p (TREE_TYPE (x));
>
> - unsigned int strict_flex_array_level = flag_strict_flex_arrays;
> -
> - tree attr_strict_flex_array = lookup_attribute ("strict_flex_array",
> - DECL_ATTRIBUTES (x));
> - /* If there is a strict_flex_array attribute attached to the field,
> - override the flag_strict_flex_arrays. */
> - if (attr_strict_flex_array)
> - {
> - /* Get the value of the level first from the attribute. */
> - unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
> - gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
> - attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
> - gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
> - attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
> - gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
> - attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
> -
> - /* The attribute has higher priority than flag_struct_flex_array. */
> - strict_flex_array_level = attr_strict_flex_array_level;
> - }
> + unsigned int strict_flex_array_level = strict_flex_array_level_of (x);
>
> switch (strict_flex_array_level)
> {
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index e312b5cef3d..5f5a6562f97 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -398,7 +398,7 @@ Objective-C and Objective-C++ Dialects}.
> -Wstrict-aliasing=n -Wstrict-overflow -Wstrict-overflow=@var{n} @gol
> -Wstring-compare @gol
> -Wno-stringop-overflow -Wno-stringop-overread @gol
> --Wno-stringop-truncation @gol
> +-Wno-stringop-truncation -Wstrict-flex-arrays @gol
> -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}malloc@r{]} @gol
> -Wswitch -Wno-switch-bool -Wswitch-default -Wswitch-enum @gol
> -Wno-switch-outside-range -Wno-switch-unreachable -Wsync-nand @gol
> @@ -7835,6 +7835,31 @@ however, are not suitable arguments to functions that expect
> such arrays GCC issues warnings unless it can prove that the use is
> safe. @xref{Common Variable Attributes}.
>
> +@item -Wstrict-flex-arrays
> +@opindex Wstrict-flex-arrays
> +@opindex Wno-strict-flex-arrays
> +Warn about inproper usages of flexible array members
> +according to the @var{level} of the @code{strict_flex_array (@var{level})}
> +attribute attached to the trailing array field of a structure if it's
> +available, otherwise according to the @var{level} of the option
> +@option{-fstrict-flex-arrays=@var{level}}.
> +
> +This option is effective only when @var{level} is bigger than 0. Otherwise,
> +it will be ignored with a warning.
> +
> +when @var{level}=1, warnings will be issued for a trailing array reference
> +of a structure that have 2 or more elements if the trailing array is referenced
> +as a flexible array member.
> +
> +when @var{level}=2, in addition to @var{level}=1, additional warnings will be
> +issued for a trailing one-element array reference of a structure
> +if the array is referenced as a flexible array member.
> +
> +when @var{level}=3, in addition to @var{level}=2, additional warnings will be
> +issued for a trailing zero-length array reference of a structure
> +if the array is referenced as a flexible array member.
> +
> +
> @item -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}cold@r{|}malloc@r{]}
> @opindex Wsuggest-attribute=
> @opindex Wno-suggest-attribute=
> @@ -8040,17 +8065,34 @@ is enabled by @option{-Wall}. It is more effective when @option{-ftree-vrp}
> is active (the default for @option{-O2} and above) but a subset of instances
> are issued even without optimization.
>
> +By default, the trailing array of a structure will be treated as a flexible
> +array member by @option{-Warray-bounds} or @option{-Warray-bounds=@var{n}}
> +if it is declared as either a flexible array member per C99 standard onwards
> +(@samp{[]}), a GCC zero-length array extension (@samp{[0]}), or an one-element
> +array (@samp{[1]}). As a result, out of bounds subscripts or offsets into
> +zero-length arrays or one-element arrays are not warned by default.
> +
> +You can add the option @option{-fstrict-flex-arrays} or
> +@option{-fstrict-flex-arrays=@var{level}} to control how this
> +option treat trailing array of a structure as a flexible array member:
> +
> +when @var{level}<=1, no change to the default behavior.
> +
> +when @var{level}=2, additional warnings will be issued for out of bounds
> +subscripts or offsets into one-element arrays;
> +
> +when @var{level}=3, in addition to @var{level}=2, additional warnings will be
> +issued for out of bounds subscripts or offsets into zero-length arrays.
> +
> @table @gcctabopt
> @item -Warray-bounds=1
> This is the default warning level of @option{-Warray-bounds} and is enabled
> by @option{-Wall}; higher levels are not, and must be explicitly requested.
>
> @item -Warray-bounds=2
> -This warning level also warns about out of bounds accesses to trailing
> -struct members of one-element array types (@pxref{Zero Length}) and about
> -the intermediate results of pointer arithmetic that may yield out of bounds
> -values. This warning level may give a larger number of false positives and
> -is deactivated by default.
> +This warning level also warns about the intermediate results of pointer
> +arithmetic that may yield out of bounds values. This warning level may
> +give a larger number of false positives and is deactivated by default.
> @end table
>
> @item -Warray-compare
> diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
> index eae49ab3910..7cf1c56ac3f 100644
> --- a/gcc/gimple-array-bounds.cc
> +++ b/gcc/gimple-array-bounds.cc
> @@ -160,38 +160,17 @@ trailing_array (tree arg, tree *pref)
> return array_ref_flexible_size_p (arg);
> }
>
> -/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
> - arrays and "struct" hacks. If VRP can determine that the array
> - subscript is a constant, check if it is outside valid range. If
> - the array subscript is a RANGE, warn if it is non-overlapping with
> - valid range. IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
> - a ADDR_EXPR. Return true if a warning has been issued or if
> - no-warning is set. */
> +/* Acquire the upper bound and upper bound plus one for the array
> + reference REF and record them into UP_BOUND and UP_BOUND_P1.
> + Set *DECL to the decl or expresssion REF refers to. */
>
> -bool
> -array_bounds_checker::check_array_ref (location_t location, tree ref,
> - gimple *stmt, bool ignore_off_by_one)
> +static void
> +get_up_bounds_for_array_ref (tree ref, tree *decl,
> + tree *up_bound, tree *up_bound_p1)
> {
> - if (warning_suppressed_p (ref, OPT_Warray_bounds))
> - /* Return true to have the caller prevent warnings for enclosing
> - refs. */
> - return true;
> -
> - tree low_sub = TREE_OPERAND (ref, 1);
> - tree up_sub = low_sub;
> - tree up_bound = array_ref_up_bound (ref);
> -
> - /* Referenced decl if one can be determined. */
> - tree decl = NULL_TREE;
> -
> - /* Set for accesses to interior zero-length arrays. */
> - special_array_member sam{ };
> -
> - tree up_bound_p1;
> -
> - if (!up_bound
> - || TREE_CODE (up_bound) != INTEGER_CST
> - || (warn_array_bounds < 2 && trailing_array (ref, &decl)))
> + if (!(*up_bound)
> + || TREE_CODE (*up_bound) != INTEGER_CST
> + || trailing_array (ref, decl))
> {
> /* Accesses to trailing arrays via pointers may access storage
> beyond the types array bounds. For such arrays, or for flexible
> @@ -203,8 +182,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> if (TREE_CODE (eltsize) != INTEGER_CST
> || integer_zerop (eltsize))
> {
> - up_bound = NULL_TREE;
> - up_bound_p1 = NULL_TREE;
> + *up_bound = NULL_TREE;
> + *up_bound_p1 = NULL_TREE;
> }
> else
> {
> @@ -217,7 +196,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> {
> /* Try to determine the size of the trailing array from
> its initializer (if it has one). */
> - if (tree refsize = component_ref_size (arg, &sam))
> + if (tree refsize = component_ref_size (arg))
> if (TREE_CODE (refsize) == INTEGER_CST)
> maxbound = refsize;
> }
> @@ -236,7 +215,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> {
> /* Try to determine the size from a pointer to
> an array if BASE is one. */
> - if (tree size = get_ref_size (base, &decl))
> + if (tree size = get_ref_size (base, decl))
> maxbound = size;
> }
> else if (!compref && DECL_P (base))
> @@ -244,7 +223,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> if (TREE_CODE (basesize) == INTEGER_CST)
> {
> maxbound = basesize;
> - decl = base;
> + *decl = base;
> }
>
> if (known_gt (off, 0))
> @@ -256,40 +235,49 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> else
> maxbound = fold_convert (sizetype, maxbound);
>
> - up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
> + *up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
>
> - if (up_bound_p1 != NULL_TREE)
> - up_bound = int_const_binop (MINUS_EXPR, up_bound_p1,
> + if (*up_bound_p1 != NULL_TREE)
> + *up_bound = int_const_binop (MINUS_EXPR, *up_bound_p1,
> build_int_cst (ptrdiff_type_node, 1));
> else
> - up_bound = NULL_TREE;
> + *up_bound = NULL_TREE;
> }
> }
> else
> - up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound,
> - build_int_cst (TREE_TYPE (up_bound), 1));
> + *up_bound_p1 = int_const_binop (PLUS_EXPR, *up_bound,
> + build_int_cst (TREE_TYPE (*up_bound), 1));
> + return;
> +}
>
> - tree low_bound = array_ref_low_bound (ref);
> +/* Given the LOW_SUB_ORG, LOW_SUB and UP_SUB, and the computed UP_BOUND
> + and UP_BOUND_P1, check whether the array reference REF is out of bound.
> + When out of bounds, set OUT_OF_BOUND to true.
> + Issue warnings if FOR_ARRAY_BOUND is true.
> + return TRUE if warnings are issued. */
>
> +static bool
> +check_out_of_bounds_and_warn (location_t location, tree ref,
> + tree low_sub_org, tree low_sub, tree up_sub,
> + tree up_bound, tree up_bound_p1,
> + const value_range *vr,
> + bool ignore_off_by_one, bool for_array_bound,
> + bool *out_of_bound)
> +{
> + tree low_bound = array_ref_low_bound (ref);
> tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
>
> bool warned = false;
> + *out_of_bound = false;
>
> /* Empty array. */
> if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
> - warned = warning_at (location, OPT_Warray_bounds,
> - "array subscript %E is outside array bounds of %qT",
> - low_sub, artype);
> -
> - const value_range *vr = NULL;
> - if (TREE_CODE (low_sub) == SSA_NAME)
> {
> - vr = get_value_range (low_sub, stmt);
> - if (!vr->undefined_p () && !vr->varying_p ())
> - {
> - low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
> - up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
> - }
> + *out_of_bound = true;
> + if (for_array_bound)
> + warned = warning_at (location, OPT_Warray_bounds,
> + "array subscript %E is outside array"
> + " bounds of %qT", low_sub_org, artype);
> }
>
> if (warned)
> @@ -303,24 +291,107 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> : tree_int_cst_le (up_bound, up_sub))
> && TREE_CODE (low_sub) == INTEGER_CST
> && tree_int_cst_le (low_sub, low_bound))
> - warned = warning_at (location, OPT_Warray_bounds,
> - "array subscript [%E, %E] is outside "
> - "array bounds of %qT",
> - low_sub, up_sub, artype);
> + {
> + *out_of_bound = true;
> + if (for_array_bound)
> + warned = warning_at (location, OPT_Warray_bounds,
> + "array subscript [%E, %E] is outside "
> + "array bounds of %qT",
> + low_sub, up_sub, artype);
> + }
> }
> else if (up_bound
> && TREE_CODE (up_sub) == INTEGER_CST
> && (ignore_off_by_one
> ? !tree_int_cst_le (up_sub, up_bound_p1)
> : !tree_int_cst_le (up_sub, up_bound)))
> - warned = warning_at (location, OPT_Warray_bounds,
> - "array subscript %E is above array bounds of %qT",
> - up_sub, artype);
> + {
> + *out_of_bound = true;
> + if (for_array_bound)
> + warned = warning_at (location, OPT_Warray_bounds,
> + "array subscript %E is above array bounds of %qT",
> + up_sub, artype);
> + }
> else if (TREE_CODE (low_sub) == INTEGER_CST
> && tree_int_cst_lt (low_sub, low_bound))
> - warned = warning_at (location, OPT_Warray_bounds,
> - "array subscript %E is below array bounds of %qT",
> - low_sub, artype);
> + {
> + *out_of_bound = true;
> + if (for_array_bound)
> + warned = warning_at (location, OPT_Warray_bounds,
> + "array subscript %E is below array bounds of %qT",
> + low_sub, artype);
> + }
> + return warned;
> +}
> +
> +/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
> + arrays and "struct" hacks. If VRP can determine that the array
> + subscript is a constant, check if it is outside valid range. If
> + the array subscript is a RANGE, warn if it is non-overlapping with
> + valid range. IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
> + a ADDR_EXPR. Return true if a warning has been issued or if
> + no-warning is set. */
> +
> +bool
> +array_bounds_checker::check_array_ref (location_t location, tree ref,
> + gimple *stmt, bool ignore_off_by_one)
> +{
> + if (warning_suppressed_p (ref, OPT_Warray_bounds))
> + /* Return true to have the caller prevent warnings for enclosing
> + refs. */
> + return true;
> +
> + /* Upper bound and Upper bound plus one for -Warray-bounds. */
> + tree up_bound = array_ref_up_bound (ref);
> + tree up_bound_p1 = NULL_TREE;
> +
> + /* Referenced decl if one can be determined. */
> + tree decl = NULL_TREE;
> +
> + /* Set to the type of the special array member for a COMPONENT_REF. */
> + special_array_member sam{ };
> +
> + tree arg = TREE_OPERAND (ref, 0);
> + const bool compref = TREE_CODE (arg) == COMPONENT_REF;
> +
> + unsigned int strict_flex_array_level = flag_strict_flex_arrays;
> +
> + if (compref)
> + {
> + /* Try to determine special array member type for this COMPONENT_REF. */
> + sam = component_ref_sam_type (arg);
> + /* Get the level of strict_flex_array for this array field. */
> + tree afield_decl = TREE_OPERAND (arg, 1);
> + strict_flex_array_level = strict_flex_array_level_of (afield_decl);
> + }
> +
> + get_up_bounds_for_array_ref (ref, &decl, &up_bound, &up_bound_p1);
> +
> + bool warned = false;
> + bool out_of_bound = false;
> +
> + tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
> + tree low_sub_org = TREE_OPERAND (ref, 1);
> + tree up_sub = low_sub_org;
> + tree low_sub = low_sub_org;
> +
> + const value_range *vr = NULL;
> + if (TREE_CODE (low_sub_org) == SSA_NAME)
> + {
> + vr = get_value_range (low_sub_org, stmt);
> + if (!vr->undefined_p () && !vr->varying_p ())
> + {
> + low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
> + up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
> + }
> + }
> +
> + warned = check_out_of_bounds_and_warn (location, ref,
> + low_sub_org, low_sub, up_sub,
> + up_bound, up_bound_p1, vr,
> + ignore_off_by_one, warn_array_bounds,
> + &out_of_bound);
> +
>
> if (!warned && sam == special_array_member::int_0)
> warned = warning_at (location, OPT_Wzero_length_bounds,
> @@ -331,19 +402,56 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
> "of an interior zero-length array %qT")),
> low_sub, artype);
>
> - if (warned)
> + if (warned || out_of_bound)
> {
> - if (dump_file && (dump_flags & TDF_DETAILS))
> + if (warned && dump_file && (dump_flags & TDF_DETAILS))
> {
> fprintf (dump_file, "Array bound warning for ");
> dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
> fprintf (dump_file, "\n");
> }
>
> + /* issue warnings for -Wstrict-flex-arrays according to the level of
> + flag_strict_flex_arrays. */
> + if (out_of_bound && warn_strict_flex_arrays)
> + switch (strict_flex_array_level)
> + {
> + case 3:
> + /* Issue additional warnings for trailing arrays [0]. */
> + if (sam == special_array_member::trail_0)
> + warned = warning_at (location, OPT_Wstrict_flex_arrays,
> + "trailing array %qT should not be used as "
> + "a flexible array member for level 3",
> + artype);
> + /* FALLTHROUGH. */
> + case 2:
> + /* Issue additional warnings for trailing arrays [1]. */
> + if (sam == special_array_member::trail_1)
> + warned = warning_at (location, OPT_Wstrict_flex_arrays,
> + "trailing array %qT should not be used as "
> + "a flexible array member for level 2 and "
> + "above", artype);
> + /* FALLTHROUGH. */
> + case 1:
> + /* Issue warnings for trailing arrays [n]. */
> + if (sam == special_array_member::trail_n)
> + warned = warning_at (location, OPT_Wstrict_flex_arrays,
> + "trailing array %qT should not be used as "
> + "a flexible array member for level 1 and "
> + "above", artype);
> + break;
> + case 0:
> + /* Do nothing. */
> + break;
> + default:
> + gcc_unreachable ();
> + }
> +
> /* Avoid more warnings when checking more significant subscripts
> of the same expression. */
> ref = TREE_OPERAND (ref, 0);
> suppress_warning (ref, OPT_Warray_bounds);
> + suppress_warning (ref, OPT_Wstrict_flex_arrays);
>
> if (decl)
> ref = decl;
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index 73fc97756e4..8db53ad6c77 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -1411,6 +1411,14 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
> opts->x_profile_flag = 0;
> }
>
> + if (opts->x_warn_strict_flex_arrays)
> + if (opts->x_flag_strict_flex_arrays == 0)
> + {
> + opts->x_warn_strict_flex_arrays = 0;
> + warning_at (UNKNOWN_LOCATION, 0,
> + "%<-Wstrict-flex-arrays%> is ignored when"
> + " %<-fstrict-flex-arrays%> does not present");
> + }
>
> diagnose_options (opts, opts_set, loc);
> }
> diff --git a/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
> new file mode 100644
> index 00000000000..72b4b7c6406
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wstrict-flex-arrays.c
> @@ -0,0 +1,9 @@
> +/* Test the usage of option -Wstrict-flex-arrays. */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays" } */
> +
> +int main(int argc, char *argv[])
> +{
> + return 0;
> +}
> +/* { dg-warning "is ignored when \'-fstrict-flex-arrays\' does not present" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-11.c b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
> index c9fc461942f..3ba2bb67fa0 100644
> --- a/gcc/testsuite/gcc.dg/Warray-bounds-11.c
> +++ b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
> @@ -78,7 +78,7 @@ void foo(int (*a)[3])
>
> h->j[4] = 1; // flexible array member
> h0->j[4] = 1; // zero-sized array extension
> - h1->j[4] = 1; /* { dg-warning "subscript 4 is above array bound" } */
> + h1->j[4] = 1; /* { dg-bogus "subscript 4 is above array bound" } */
> h3->j[4] = 1; /* { dg-warning "subscript 4 is above array bound" } */
>
> struct h0b* h0b = malloc(sizeof(struct h) + 3 * sizeof(int));
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
> new file mode 100644
> index 00000000000..59d5a5fcb23
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-2.c
> @@ -0,0 +1,46 @@
> +/* Test -Wstrict-flex-arrays. */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2" } */
> +
> +struct trailing_array_1 {
> + int a;
> + int b;
> + int c[4];
> +};
> +
> +struct trailing_array_2 {
> + int a;
> + int b;
> + int c[1];
> +};
> +
> +struct trailing_array_3 {
> + int a;
> + int b;
> + int c[0];
> +};
> +struct trailing_array_4 {
> + int a;
> + int b;
> + int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> + struct trailing_array_1 *normal,
> + struct trailing_array_2 *trailing_1,
> + struct trailing_array_3 *trailing_0,
> + struct trailing_array_4 *trailing_flex)
> +{
> + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> + trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> + trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
> new file mode 100644
> index 00000000000..2f66151e927
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-3.c
> @@ -0,0 +1,46 @@
> +/* Test -Wstrict-flex-arrays. */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3" } */
> +
> +struct trailing_array_1 {
> + int a;
> + int b;
> + int c[4];
> +};
> +
> +struct trailing_array_2 {
> + int a;
> + int b;
> + int c[1];
> +};
> +
> +struct trailing_array_3 {
> + int a;
> + int b;
> + int c[0];
> +};
> +struct trailing_array_4 {
> + int a;
> + int b;
> + int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> + struct trailing_array_1 *normal,
> + struct trailing_array_2 *trailing_1,
> + struct trailing_array_3 *trailing_0,
> + struct trailing_array_4 *trailing_flex)
> +{
> + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> + trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> + trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
> + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
> new file mode 100644
> index 00000000000..8ea6236b4f7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-4.c
> @@ -0,0 +1,47 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds. */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1 -Warray-bounds" } */
> +
> +struct trailing_array_1 {
> + int a;
> + int b;
> + int c[4];
> +};
> +
> +struct trailing_array_2 {
> + int a;
> + int b;
> + int c[1];
> +};
> +
> +struct trailing_array_3 {
> + int a;
> + int b;
> + int c[0];
> +};
> +struct trailing_array_4 {
> + int a;
> + int b;
> + int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> + struct trailing_array_1 *normal,
> + struct trailing_array_2 *trailing_1,
> + struct trailing_array_3 *trailing_0,
> + struct trailing_array_4 *trailing_flex)
> +{
> + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> + /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> + trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> + trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
> new file mode 100644
> index 00000000000..00f4037d03c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-5.c
> @@ -0,0 +1,49 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds. */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2 -Warray-bounds" } */
> +
> +struct trailing_array_1 {
> + int a;
> + int b;
> + int c[4];
> +};
> +
> +struct trailing_array_2 {
> + int a;
> + int b;
> + int c[1];
> +};
> +
> +struct trailing_array_3 {
> + int a;
> + int b;
> + int c[0];
> +};
> +struct trailing_array_4 {
> + int a;
> + int b;
> + int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> + struct trailing_array_1 *normal,
> + struct trailing_array_2 *trailing_1,
> + struct trailing_array_3 *trailing_0,
> + struct trailing_array_4 *trailing_flex)
> +{
> + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> + /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> + trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> + /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
> +
> + trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
> new file mode 100644
> index 00000000000..190dd0d89c2
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-6.c
> @@ -0,0 +1,49 @@
> +/* Test -Wstrict-flex-arrays. */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3 -Warray-bounds" } */
> +
> +struct trailing_array_1 {
> + int a;
> + int b;
> + int c[4];
> +};
> +
> +struct trailing_array_2 {
> + int a;
> + int b;
> + int c[1];
> +};
> +
> +struct trailing_array_3 {
> + int a;
> + int b;
> + int c[0];
> +};
> +struct trailing_array_4 {
> + int a;
> + int b;
> + int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> + struct trailing_array_1 *normal,
> + struct trailing_array_2 *trailing_1,
> + struct trailing_array_3 *trailing_0,
> + struct trailing_array_4 *trailing_flex)
> +{
> + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> + /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> + trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> + /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
> + trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
> + /*{ dg-warning "array subscript 1 is outside array bounds of" "" { target *-*-* } .-1 } */
> + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
> new file mode 100644
> index 00000000000..f422705e09f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-7.c
> @@ -0,0 +1,48 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds=2. */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1 -Warray-bounds=2" } */
> +
> +struct trailing_array_1 {
> + int a;
> + int b;
> + int c[4];
> +};
> +
> +struct trailing_array_2 {
> + int a;
> + int b;
> + int c[1];
> +};
> +
> +struct trailing_array_3 {
> + int a;
> + int b;
> + int c[0];
> +};
> +struct trailing_array_4 {
> + int a;
> + int b;
> + int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> + struct trailing_array_1 *normal,
> + struct trailing_array_2 *trailing_1,
> + struct trailing_array_3 *trailing_0,
> + struct trailing_array_4 *trailing_flex)
> +{
> + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> + /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> + trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> + /*{ dg-bogus "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
> + trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
> new file mode 100644
> index 00000000000..e9bbd03dd9a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-8.c
> @@ -0,0 +1,48 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds=2. */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=2 -Warray-bounds=2" } */
> +
> +struct trailing_array_1 {
> + int a;
> + int b;
> + int c[4];
> +};
> +
> +struct trailing_array_2 {
> + int a;
> + int b;
> + int c[1];
> +};
> +
> +struct trailing_array_3 {
> + int a;
> + int b;
> + int c[0];
> +};
> +struct trailing_array_4 {
> + int a;
> + int b;
> + int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> + struct trailing_array_1 *normal,
> + struct trailing_array_2 *trailing_1,
> + struct trailing_array_3 *trailing_0,
> + struct trailing_array_4 *trailing_flex)
> +{
> + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> + /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> + trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> + /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
> + trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 2 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
> new file mode 100644
> index 00000000000..54e8de4b04f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays-9.c
> @@ -0,0 +1,49 @@
> +/* Test -Wstrict-flex-arrays + -Warray-bounds=2. */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=3 -Warray-bounds=2" } */
> +
> +struct trailing_array_1 {
> + int a;
> + int b;
> + int c[4];
> +};
> +
> +struct trailing_array_2 {
> + int a;
> + int b;
> + int c[1];
> +};
> +
> +struct trailing_array_3 {
> + int a;
> + int b;
> + int c[0];
> +};
> +struct trailing_array_4 {
> + int a;
> + int b;
> + int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> + struct trailing_array_1 *normal,
> + struct trailing_array_2 *trailing_1,
> + struct trailing_array_3 *trailing_0,
> + struct trailing_array_4 *trailing_flex)
> +{
> + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> + /*{ dg-warning "array subscript 5 is above array bounds of" "" { target *-*-* } .-1 } */
> + trailing_1->c[2] = 2; /* { dg-warning "should not be used as a flexible array member for level 2 and above" } */
> + /*{ dg-warning "array subscript 2 is above array bounds of" "" { target *-*-* } .-1 } */
> + trailing_0->c[1] = 1; /* { dg-warning "should not be used as a flexible array member for level 3" } */
> + /*{ dg-warning "array subscript 1 is outside array bounds of" "" { target *-*-* } .-1 } */
> + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 3" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> + return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
> new file mode 100644
> index 00000000000..43a9098f138
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/Wstrict-flex-arrays.c
> @@ -0,0 +1,46 @@
> +/* Test -Wstrict-flex-arrays. */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -Wstrict-flex-arrays -fstrict-flex-arrays=1" } */
> +
> +struct trailing_array_1 {
> + int a;
> + int b;
> + int c[4];
> +};
> +
> +struct trailing_array_2 {
> + int a;
> + int b;
> + int c[1];
> +};
> +
> +struct trailing_array_3 {
> + int a;
> + int b;
> + int c[0];
> +};
> +struct trailing_array_4 {
> + int a;
> + int b;
> + int c[];
> +};
> +
> +void __attribute__((__noinline__)) stuff(
> + struct trailing_array_1 *normal,
> + struct trailing_array_2 *trailing_1,
> + struct trailing_array_3 *trailing_0,
> + struct trailing_array_4 *trailing_flex)
> +{
> + normal->c[5] = 5; /*{ dg-warning "should not be used as a flexible array member for level 1 and above" } */
> + trailing_1->c[2] = 2; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> + trailing_0->c[1] = 1; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> + trailing_flex->c[10] = 10; /* { dg-bogus "should not be used as a flexible array member for level 1 and above" } */
> +
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + stuff((void *)argv[0], (void *)argv[0], (void *)argv[0], (void *)argv[0]);
> +
> + return 0;
> +}
> diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
> index 3846dc1d849..e6c6c5a301d 100644
> --- a/gcc/tree-vrp.cc
> +++ b/gcc/tree-vrp.cc
> @@ -1087,7 +1087,7 @@ execute_ranger_vrp (struct function *fun, bool warn_array_bounds_p,
> if (dump_file && (dump_flags & TDF_DETAILS))
> ranger->dump (dump_file);
>
> - if (warn_array_bounds && warn_array_bounds_p)
> + if ((warn_array_bounds || warn_strict_flex_arrays) && warn_array_bounds_p)
> {
> // Set all edges as executable, except those ranger says aren't.
> int non_exec_flag = ranger->non_executable_edge_flag;
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index 254b2373dcf..b40c95ae8c4 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -12719,15 +12719,21 @@ array_ref_up_bound (tree exp)
> int test (uint8_t *p, uint32_t t[1][1], int n) {
> for (int i = 0; i < 4; i++, p++)
> t[i][0] = ...;
> +
> + If non-null, set IS_TRAILING_ARRAY to true if the ref is the above case A.
> */
>
> bool
> -array_ref_flexible_size_p (tree ref)
> +array_ref_flexible_size_p (tree ref, bool *is_trailing_array /* = NULL */)
> {
> - /* the TYPE for this array referece. */
> + /* The TYPE for this array referece. */
> tree atype = NULL_TREE;
> - /* the FIELD_DECL for the array field in the containing structure. */
> + /* The FIELD_DECL for the array field in the containing structure. */
> tree afield_decl = NULL_TREE;
> + /* Whether this array is the trailing array of a structure. */
> + bool is_trailing_array_tmp = false;
> + if (!is_trailing_array)
> + is_trailing_array = &is_trailing_array_tmp;
>
> if (TREE_CODE (ref) == ARRAY_REF
> || TREE_CODE (ref) == ARRAY_RANGE_REF)
> @@ -12815,7 +12821,10 @@ array_ref_flexible_size_p (tree ref)
> if (! TYPE_SIZE (atype)
> || ! TYPE_DOMAIN (atype)
> || ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
> - return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> + {
> + *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> + }
>
> /* If the reference is based on a declared entity, the size of the array
> is constrained by its given domain. (Do not trust commons PR/69368). */
> @@ -12837,9 +12846,17 @@ array_ref_flexible_size_p (tree ref)
> if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (atype))) != INTEGER_CST
> || TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST
> || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST)
> - return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> + {
> + *is_trailing_array
> + = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> + }
> if (! get_addr_base_and_unit_offset (ref_to_array, &offset))
> - return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> + {
> + *is_trailing_array
> + = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> + }
>
> /* If at least one extra element fits it is a flexarray. */
> if (known_le ((wi::to_offset (TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
> @@ -12847,11 +12864,16 @@ array_ref_flexible_size_p (tree ref)
> + 2)
> * wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))),
> wi::to_offset (DECL_SIZE_UNIT (ref)) - offset))
> - return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> + {
> + *is_trailing_array
> + = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> + return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> + }
>
> return false;
> }
>
> + *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
> return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
> }
>
> @@ -12913,11 +12935,63 @@ get_initializer_for (tree init, tree decl)
> return NULL_TREE;
> }
>
> +/* Determines the special array member type for the array reference REF. */
> +special_array_member
> +component_ref_sam_type (tree ref)
> +{
> + special_array_member sam_type = special_array_member::none;
> +
> + tree member = TREE_OPERAND (ref, 1);
> + tree memsize = DECL_SIZE_UNIT (member);
> + if (memsize)
> + {
> + tree memtype = TREE_TYPE (member);
> + if (TREE_CODE (memtype) != ARRAY_TYPE)
> + return sam_type;
> +
> + bool trailing = false;
> + (void)array_ref_flexible_size_p (ref, &trailing);
> + bool zero_length = integer_zerop (memsize);
> + if (!trailing && !zero_length)
> + /* MEMBER is an interior array with
> + more than one element. */
> + return special_array_member::int_n;
> +
> + if (zero_length)
> + {
> + if (trailing)
> + return special_array_member::trail_0;
> + else
> + return special_array_member::int_0;
> + }
> +
> + if (!zero_length)
> + if (tree dom = TYPE_DOMAIN (memtype))
> + if (tree min = TYPE_MIN_VALUE (dom))
> + if (tree max = TYPE_MAX_VALUE (dom))
> + if (TREE_CODE (min) == INTEGER_CST
> + && TREE_CODE (max) == INTEGER_CST)
> + {
> + offset_int minidx = wi::to_offset (min);
> + offset_int maxidx = wi::to_offset (max);
> + offset_int neltsm1 = maxidx - minidx;
> + if (neltsm1 > 0)
> + /* MEMBER is a trailing array with more than
> + one elements. */
> + return special_array_member::trail_n;
> +
> + if (neltsm1 == 0)
> + return special_array_member::trail_1;
> + }
> + }
> +
> + return sam_type;
> +}
> +
> /* Determines the size of the member referenced by the COMPONENT_REF
> REF, using its initializer expression if necessary in order to
> determine the size of an initialized flexible array member.
> - If non-null, set *ARK when REF refers to an interior zero-length
> - array or a trailing one-element array.
> + If non-null, set *SAM to the type of special array member.
> Returns the size as sizetype (which might be zero for an object
> with an uninitialized flexible array member) or null if the size
> cannot be determined. */
> @@ -12930,7 +13004,7 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
> special_array_member sambuf;
> if (!sam)
> sam = &sambuf;
> - *sam = special_array_member::none;
> + *sam = component_ref_sam_type (ref);
>
> /* The object/argument referenced by the COMPONENT_REF and its type. */
> tree arg = TREE_OPERAND (ref, 0);
> @@ -12951,43 +13025,46 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
> return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype))
> ? memsize : NULL_TREE);
>
> - bool trailing = array_ref_flexible_size_p (ref);
> - bool zero_length = integer_zerop (memsize);
> - if (!trailing && !zero_length)
> - /* MEMBER is either an interior array or is an array with
> - more than one element. */
> + /* 2-or-more elements arrays are treated as normal arrays by default. */
> + if (*sam == special_array_member::int_n
> + || *sam == special_array_member::trail_n)
> return memsize;
>
> - if (zero_length)
> + /* flag_strict_flex_arrays will control how to treat
> + the trailing arrays as flexiable array members. */
> +
> + tree afield_decl = TREE_OPERAND (ref, 1);
> + unsigned int strict_flex_array_level
> + = strict_flex_array_level_of (afield_decl);
> +
> + switch (strict_flex_array_level)
> {
> - if (trailing)
> - *sam = special_array_member::trail_0;
> - else
> - {
> - *sam = special_array_member::int_0;
> - memsize = NULL_TREE;
> - }
> + case 3:
> + /* Treaing 0-length trailing arrays as normal array. */
> + if (*sam == special_array_member::trail_0)
> + return size_zero_node;
> + /* FALLTHROUGH. */
> + case 2:
> + /* Treating 1-element trailing arrays as normal array. */
> + if (*sam == special_array_member::trail_1)
> + return memsize;
> + /* FALLTHROUGH. */
> + case 1:
> + /* Treating 2-or-more elements trailing arrays as normal
> + array. */
> + if (*sam == special_array_member::trail_n)
> + return memsize;
> + /* FALLTHROUGH. */
> + case 0:
> + break;
> + default:
> + gcc_unreachable ();
> }
>
> - if (!zero_length)
> - if (tree dom = TYPE_DOMAIN (memtype))
> - if (tree min = TYPE_MIN_VALUE (dom))
> - if (tree max = TYPE_MAX_VALUE (dom))
> - if (TREE_CODE (min) == INTEGER_CST
> - && TREE_CODE (max) == INTEGER_CST)
> - {
> - offset_int minidx = wi::to_offset (min);
> - offset_int maxidx = wi::to_offset (max);
> - offset_int neltsm1 = maxidx - minidx;
> - if (neltsm1 > 0)
> - /* MEMBER is an array with more than one element. */
> - return memsize;
> -
> - if (neltsm1 == 0)
> - *sam = special_array_member::trail_1;
> - }
> + if (*sam == special_array_member::int_0)
> + memsize = NULL_TREE;
>
> - /* For a reference to a zero- or one-element array member of a union
> + /* For a reference to a flexible array member of a union
> use the size of the union instead of the size of the member. */
> if (TREE_CODE (argtype) == UNION_TYPE)
> memsize = TYPE_SIZE_UNIT (argtype);
> diff --git a/gcc/tree.h b/gcc/tree.h
> index 4a19de1c94d..23223ca0c87 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -5553,22 +5553,26 @@ extern tree array_ref_low_bound (tree);
> /* Returns true if REF is an array reference, a component reference,
> or a memory reference to an array whose actual size might be larger
> than its upper bound implies. */
> -extern bool array_ref_flexible_size_p (tree);
> +extern bool array_ref_flexible_size_p (tree, bool * = NULL);
>
> /* Return a tree representing the offset, in bytes, of the field referenced
> by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */
> extern tree component_ref_field_offset (tree);
>
> -/* Describes a "special" array member due to which component_ref_size
> - returns null. */
> +/* Describes a "special" array member for a COMPONENT_REF. */
> enum struct special_array_member
> {
> none, /* Not a special array member. */
> int_0, /* Interior array member with size zero. */
> trail_0, /* Trailing array member with size zero. */
> - trail_1 /* Trailing array member with one element. */
> + trail_1, /* Trailing array member with one element. */
> + trail_n, /* Trailing array member with two or more elements. */
> + int_n /* Interior array member with one or more elements. */
> };
>
> +/* Determines the special array member type for a COMPONENT_REF. */
> +extern special_array_member component_ref_sam_type (tree);
> +
> /* Return the size of the member referenced by the COMPONENT_REF, using
> its initializer expression if necessary in order to determine the size
> of an initialized flexible array member. The size might be zero for
> --
> 2.31.1
>
next prev parent reply other threads:[~2022-12-06 16:16 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-12-06 16:14 [V3][PATCH 0/2]Update -Warray-bounds with -fstrict-flex-arrays Qing Zhao
2022-12-06 16:14 ` [V2][PATCH 1/1] Add a new warning option -Wstrict-flex-arrays Qing Zhao
2022-12-06 16:16 ` Qing Zhao [this message]
2022-12-06 16:14 ` [V3][PATCH 1/2] Update -Warray-bounds with -fstrict-flex-arrays Qing Zhao
2022-12-06 16:22 ` Richard Biener
-- strict thread matches above, loose matches on Subject: below --
2022-11-30 14:25 [V2][PATCH 0/1]Add a new warning option -Wstrict-flex-arrays Qing Zhao
2022-11-30 14:25 ` [V2][PATCH 1/1] Add " Qing Zhao
2022-12-01 16:42 ` Kees Cook
2022-12-01 17:04 ` Qing Zhao
2022-12-01 17:18 ` Kees Cook
2022-12-01 17:48 ` Qing Zhao
2022-12-01 19:45 ` Siddhesh Poyarekar
2022-12-01 22:27 ` Qing Zhao
2022-12-01 23:19 ` Kees Cook
2022-12-01 23:53 ` Siddhesh Poyarekar
2022-12-02 7:16 ` Richard Biener
2022-12-02 7:20 ` Richard Biener
2022-12-02 14:43 ` Qing Zhao
2022-12-05 15:16 ` Richard Biener
2022-12-05 15:20 ` Qing Zhao
2022-12-02 14:40 ` Qing Zhao
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=FCBB5262-0DD4-4F87-8B31-FCECF57B7C6B@oracle.com \
--to=qing.zhao@oracle.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=joseph@codesourcery.com \
--cc=rguenther@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).