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

--- Comment #6 from Martin Sebor <msebor at gcc dot gnu.org> ---
(In reply to Nate Eldredge from comment #4)

A compile-time only test that doesn't depend on the target or endianness would
be much better than a runtime test that fails only on a subset of targets.  The
way to do that is to verify that the pass doesn't misinterpret the size of the
pointer stored in the array as the length of the string by checking to make
sure that the result of a strlen call with the buffer as an argument isn't
folded into a constant:

/* PR tree-optimization/94015 - assignment incorrectly omitted by
   -foptimize-strlen
   { dg-do compile }
   { dg-options "-O2 -Wall -fdump-tree-optimized" } */

int f (int n)
{
  char *s = __builtin_malloc (n);
  *(char **)s = "0123456";
  return __builtin_strlen (s);
}

/* { dg-final { scan-tree-dump-times "strlen" 1 "optimized" } } */


The buggy count_nonzero_bytes function is tricky because it tries to recover
string length information obscured by earlier optimizations like store merging
that turn multiple character stores into one.  The merged stores can have
different forms, be of a variety of different types, and result in ranges of
lengths (i.e., minimum and maximum).  For instance this:

  char a[8];

  void f (void)
  {
    char s[] = "1234567";
    __builtin_memcpy (a, s, sizeof s);
  }

is transformed into this:

  f (char * p)
  {
    <bb 2> [local count: 1073741824]:
    MEM <long unsigned int> [(char * {ref-all})&a] = 15540725856023089;
    return;
  }

count_nonzero_bytes then goes and figures out the length of the string the
number corresponds to.  To detect buffer overflows, it also computes the size
of the store, and when the store is one of a pointer type, it gets the size and
length computations mixed up.

Reply via email to