Bug 91490

Summary: [9 Regression] bogus argument missing terminating nul warning on strlen of a flexible array member
Product: gcc Reporter: Martin Sebor <msebor>
Component: middle-endAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: jbeulich, wielkiegie
Priority: P3 Keywords: diagnostic, missed-optimization, patch
Version: 9.0   
Target Milestone: 10.0   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2019-08-21 00:00:00
Bug Depends on:    
Bug Blocks: 69698, 83819, 88443    

Description Martin Sebor 2019-08-19 15:06:40 UTC
The strlen call in f() below compiles with no warning and is successfully folded to a constant, but the equivalent call in g() triggers two spurious instances of the same warning and is not folded.

The warning is new in GCC 9 so GCC 8 compiles both functions without one, and folds neither call,

$ cat a.c && gcc -O2 -S -Wall -Wextra -fdump-tree-optimized=/dev/stdout a.c
struct A { char n, s[]; };

const struct A a1 = { 3, "321" };

int f (void)
{
  return __builtin_strlen (a1.s);   // no warning, folded to 3
}

const struct A a2 = { 3, { 3, 2, 1, 0 } };
  
int g (void)
{
  return __builtin_strlen (a2.s);   // bogus warning, not folded
}

a.c: In function ‘g’:
a.c:14:30: warning: ‘strlen’ argument missing terminating nul [-Wstringop-overflow=]
   14 |   return __builtin_strlen (a2.s);   // bogus warning, not folded
      |                            ~~^~
a.c:10:16: note: referenced argument declared here
   10 | const struct A a2 = { 3, { 3, 2, 1, 0 } };
      |                ^~
a.c:14:30: warning: ‘strlen’ argument missing terminating nul [-Wstringop-overflow=]
   14 |   return __builtin_strlen (a2.s);   // bogus warning, not folded
      |                            ~~^~
a.c:10:16: note: referenced argument declared here
   10 | const struct A a2 = { 3, { 3, 2, 1, 0 } };
      |                ^~

;; Function f (f, funcdef_no=0, decl_uid=1910, cgraph_uid=1, symbol_order=1)

f ()
{
  <bb 2> [local count: 1073741824]:
  return 3;

}



;; Function g (g, funcdef_no=1, decl_uid=1914, cgraph_uid=2, symbol_order=3)

g ()
{
  long unsigned int _1;
  int _3;

  <bb 2> [local count: 1073741824]:
  _1 = __builtin_strlen (&a2.s);
  _3 = (int) _1;
  return _3;

}
Comment 1 Martin Sebor 2019-08-21 16:34:50 UTC
Patch: https://gcc.gnu.org/ml/gcc-patches/2019-08/msg01202.html
Comment 2 Martin Sebor 2019-08-21 20:51:20 UTC
A subset of the patch referenced in comment #1 that deals with just this issue:
https://gcc.gnu.org/ml/gcc-patches/2019-08/msg01517.html
Comment 3 Martin Sebor 2019-08-22 23:10:02 UTC
Author: msebor
Date: Thu Aug 22 23:09:26 2019
New Revision: 274837

URL: https://gcc.gnu.org/viewcvs?rev=274837&root=gcc&view=rev
Log:
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 and unions.

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.
	Fold empty and zero constructors into empty strings.
	* 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.


Added:
    trunk/gcc/testsuite/c-c++-common/Warray-bounds-7.c
    trunk/gcc/testsuite/gcc.dg/strlenopt-78.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/builtins.c
    trunk/gcc/c-family/ChangeLog
    trunk/gcc/c-family/c-common.c
    trunk/gcc/expr.c
    trunk/gcc/gimple-fold.c
    trunk/gcc/gimple-ssa-warn-restrict.c
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/gcc.dg/Warray-bounds-39.c
    trunk/gcc/tree.c
    trunk/gcc/tree.h
Comment 4 Martin Sebor 2019-08-22 23:23:21 UTC
Fixed in r274837.  I'm not sure this should be backported.  It suppresses bogus warnings but also introduces new warnings for invalid code.
Comment 5 Martin Sebor 2019-09-05 22:34:39 UTC
*** Bug 91667 has been marked as a duplicate of this bug. ***
Comment 6 programmer 2019-09-20 13:14:32 UTC
The same bogus warning ist produced by "g++ -Wall" with the C++ code below. Note that flexible array members are not involved there.

GCC 9.2 is affected: https://godbolt.org/z/j9m4XS
GCC 10 seems fixed: https://godbolt.org/z/DPrR1Z

//////////////////////////////////////////////////////////////////////////////

struct two_chars_t {// std::array<char, 2>
  char data_[2];
  constexpr const char* data() const { return data_; }
};

constexpr two_chars_t global_x0  = two_chars_t{'x', '\0'};

int main() {
  constexpr const char* pointer = global_x0.data();

  static_assert(pointer[0] == 'x');
  static_assert(pointer[1] == '\0');

  return __builtin_strlen(pointer);
}

//////////////////////////////////////////////////////////////////////////////
Comment 7 Jakub Jelinek 2020-03-12 11:58:56 UTC
GCC 9.3.0 has been released, adjusting target milestone.
Comment 8 Gustaw Smolarczyk 2020-09-04 10:58:34 UTC
Bug 96934 is potentially related to this issue, but I have also found a miscompilation of strcmp call that is possibly related.
Comment 9 Richard Biener 2021-06-01 08:15:07 UTC
GCC 9.4 is being released, retargeting bugs to GCC 9.5.
Comment 10 Martin Sebor 2022-03-17 19:57:17 UTC
I'm no longer planning to backport the fix.
Comment 11 Richard Biener 2022-05-27 08:37:34 UTC
Fixed in GCC 10.