https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103835

Martin Sebor <msebor at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|Bogus sprintf warnings      |bogus sprintf warnings due
                   |                            |to missing strlen
                   |                            |propagation
             Blocks|                            |83819

--- Comment #3 from Martin Sebor <msebor at gcc dot gnu.org> ---
The warnings in comment #0 are caused by a limitation of the strlen/sprintf
passes: their less than perfect integration with the range (or constant)
propagation machinery.  The issue can be seen in the simplified test case
below.  In f() the constant strlen() result isn't propagated into the addition
in d_5 = &a + n_4; at the time the warning runs (within the strlen pass), and
so it triggers as expected.  In g() it is propagated and the warning doesn't
trigger.

To avoid the warnings the strlen pass needs to set the range of strlen results
and propagate them through the IL so they can be determined in computations in
subsequent statements (like sprintf).

$ cat pr103835.c && gcc -O2 -S -Wall -fdump-tree-strlen=/dev/stdout pr103835.c
char a[8];

int f (void)
{
  __builtin_strcpy (a, "f");

  __SIZE_TYPE__ n = __builtin_strlen (a) + 1;

  char *d = a + n;

 __builtin_sprintf (d, "%s", a);

  return n;
}

int g (void)
{
  __builtin_strcpy (a, "g");

  __SIZE_TYPE__ n = __builtin_strlen ("g") + 1;

  char *d = a + n;

 __builtin_sprintf (d, "%s", a);

  return n;
}


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

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }
pr103835.c:11: __builtin_sprintf: objsize = 6, fmtstr = "%s"
  Directive 1 at offset 0: "%s"
    Result: 1, 1, 1, 1 (1, 1, 1, 1)
  Directive 2 at offset 2: "", length = 1
pr103835.c: In function ‘f’:
pr103835.c:11:2: warning: ‘__builtin_sprintf’ argument 3 may overlap
destination object ‘a’ [-Wrestrict]
   11 |  __builtin_sprintf (d, "%s", a);
      |  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pr103835.c:1:6: note: destination object referenced by ‘restrict’-qualified
argument 1 was declared here
    1 | char a[8];
      |      ^

int f ()
{
  char * d;
  long unsigned int n;
  long unsigned int _1;
  int _7;

  <bb 2> [local count: 1073741824]:
  __builtin_memcpy (&a, "f", 2);
  _1 = 1;
  n_4 = _1 + 1;
  d_5 = &a + n_4;
  __builtin_strcpy (d_5, &a);
  _7 = (int) n_4;
  return _7;

}



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

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }
pr103835.c:24: __builtin_sprintf: objsize = 6, fmtstr = "%s"
  Directive 1 at offset 0: "%s"
    Result: 1, 1, 1, 1 (1, 1, 1, 1)
  Directive 2 at offset 2: "", length = 1
  Substituting 1 for return value.

int g ()
{
  <bb 2> [local count: 1073741824]:
  __builtin_memcpy (&a, "g", 2);
  __builtin_strcpy (&MEM <char[8]> [(void *)&a + 2B], &a);
  return 2;

}


Referenced Bugs:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83819
[Bug 83819] [meta-bug] missing strlen optimizations

Reply via email to