On 8/22/19 3:27 PM, Jeff Law wrote:
On 8/21/19 2:50 PM, Martin Sebor wrote:
This patch is a subset of the solution for PR 91457 whose main
goal is to eliminate inconsistencies in warnings issued for
out-of-bounds accesses to the various flavors of flexible array
members of constant objects.  That patch was posted here:
   https://gcc.gnu.org/ml/gcc-patches/2019-08/msg01202.html

Like PR 91457, this patch also relies on improving optimization
to issue better quality warnings.  (I.e., with the latter being
what motivated it.)

The optimization enhances string_constant to recognize empty
CONSTRUCTORs returned by fold_ctor_reference for references
to members of constant objects with either "insufficient"
initializers (e.g., given struct S { char n, a[]; } s = { 0 };)
or with braced-list initializers (e.g., given
struct S s = { 3 { 1, 2, 3, 0 } };  The patch lets string_constant
convert the CONSTRUCTOR for s.a into a STRING_CST, which in turn
enables the folding of calls to built-ins like strlen, strchr, or
strcmp with such arguments.

Exposing the strings to the folder then also lets it detect and
issue warnings for out-of-bounds offsets in more instances of
such references than before.

The remaining changes in the patch mostly enhance the places
that use the no-warning bit to prevent redundant diagnostics.

Tested on x86_64-linux.

Martin

gcc-91490.diff

PR middle-end/91490 - bogus argument missing terminating nul warning on strlen 
of a flexible array member

gcc/c-family/ChangeLog:

        PR middle-end/91490
        * c-common.c (braced_list_to_string): Add argument and overload.
        Handle flexible length arrays.

gcc/testsuite/ChangeLog:

        PR middle-end/91490
        * c-c++-common/Warray-bounds-7.c: New test.
        * gcc.dg/Warray-bounds-39.c: Expect either -Warray-bounds or
        -Wstringop-overflow.
        * gcc.dg/strlenopt-78.c: New test.

gcc/ChangeLog:

        PR middle-end/91490
        * builtins.c (c_strlen): Rename argument and introduce new local.
        Set no-warning bit on original argument.
        * expr.c (string_constant): Pass argument type to fold_ctor_reference.
        * gimple-fold.c (fold_nonarray_ctor_reference): Return a STRING_CST
        for missing initializers.
        * tree.c (build_string_literal): Handle optional argument.
        * tree.h (build_string_literal): Add defaulted argument.
        * gimple-ssa-warn-restrict.c (maybe_diag_access_bounds): Check
        no-warning bit on original expression.

diff --git a/gcc/builtins.c b/gcc/builtins.c
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -11402,6 +11402,16 @@ is_aligning_offset (const_tree offset, const_tree exp)
  tree
  string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
  {
+  tree dummy = NULL_TREE;;
+  if (!mem_size)
+    mem_size = &dummy;
+
+  tree chartype = TREE_TYPE (arg);
+  if (POINTER_TYPE_P (chartype))
+    chartype = TREE_TYPE (chartype);
+  while (TREE_CODE (chartype) == ARRAY_TYPE)
+    chartype = TREE_TYPE (chartype);
+
    tree array;
    STRIP_NOPS (arg);
So per our conversation today, I took a closer look at this.  As you
noted CHARTYPE is only used for the empty constructor code you're adding
as a part of this patch.

Rather than stripping away types like this to compute chartype, couldn't
we just use char_type_node instead of chartype in this code below?

We can't.  string_constant is also called for wide strings (e.g.,
by the sprintf pass).  Returning a narrow string when the caller
asks for a wide one breaks the sprintf stuff.


+  tree initsize = TYPE_SIZE_UNIT (inittype);
+
+  if (TREE_CODE (init) == CONSTRUCTOR && !CONSTRUCTOR_ELTS (init))
+    {
+      /* Convert a char array to an empty STRING_CST having an array
+        of the expected type.  */
+      if (!initsize)
+         initsize = integer_zero_node;
+
+      unsigned HOST_WIDE_INT size = tree_to_uhwi (initsize);
+      init = build_string_literal (size ? 1 : 0, "", chartype, size);
+      init = TREE_OPERAND (init, 0);
+      init = TREE_OPERAND (init, 0);
+
+      *ptr_offset = integer_zero_node;
+    }
Per my prior message, we do need to update that test to be something like

if (TREE_CODE (init) == CONSTRUCTOR
     && !CONSTRUCTOR_ELTS
     && !TREE_CLOBBER_P (init))

While I don't think we're likely to see a TREE_CLOBBER_P here, it's best
to be safe since those have totally different meanings,

I went with the other alternative you mentioned and used
initializer_zerop as I explained in my reply.  Let me know if
that's not what you meant.


diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 2810867235d..ef942ffce57 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -8868,7 +8876,7 @@ braced_lists_to_strings (tree type, tree ctor)
        unsigned HOST_WIDE_INT idx;
        FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), idx, val)
        {
-         val = braced_lists_to_strings (ttp, val);
+         val = braced_lists_to_strings (ttp, val, code == RECORD_TYPE);
Also per our discussion, I think a comment that we might want to test
RECORD_OR_UNION_TYPE_P here instead of just testing for RECORD_TYPE is
all we need.

With those changes and a bootstrap/regression test, this is OK.

I just sent an updated patch with most of these changes.  I'll
wait to until tomorrow to commit it in cases there are further
comments.

Thanks
Martin

Reply via email to