strlen: Punt on UB reads past end of string literal [PR94187]
authorJakub Jelinek <jakub@redhat.com>
Tue, 17 Mar 2020 09:43:46 +0000 (10:43 +0100)
committerJakub Jelinek <jakub@redhat.com>
Tue, 17 Mar 2020 09:43:46 +0000 (10:43 +0100)
The gcc.dg/pr68785.c test which contains:
int
foo (void)
{
  return *(int *) "";
}
has UB in the program if it is ever called, but causes UB in the compiler
as well as at least in theory non-reproduceable code generation.
The problem is that nbytes is in this case 4, prep is the
TREE_STRING_POINTER of a "" string literal with TREE_STRING_LENGTH of 1 and
we do:
4890              for (const char *p = prep; p != prep + nbytes; ++p)
4891                if (*p)
4892                  {
4893                    *allnul = false;
4894                    break;
4895                  }
and so read the bytes after the STRING_CST payload, which can be random.
I think we should just punt in this case.

2020-03-17  Jakub Jelinek  <jakub@redhat.com>

PR tree-optimization/94187
* tree-ssa-strlen.c (count_nonzero_bytes): Punt if
nchars - offset < nbytes.

gcc/ChangeLog
gcc/tree-ssa-strlen.c

index fc35ceac272a80eede3b18278b0f6fd0dffbac3e..f8105ccc67d9584894184aad0424fee9e2501fc3 100644 (file)
@@ -1,5 +1,9 @@
 2020-03-17  Jakub Jelinek  <jakub@redhat.com>
 
+       PR tree-optimization/94187
+       * tree-ssa-strlen.c (count_nonzero_bytes): Punt if
+       nchars - offset < nbytes.
+
        PR middle-end/94189
        * builtins.c (expand_builtin_strnlen): Do return NULL_RTX if we would
        emit a warning if it was enabled and don't depend on TREE_NO_WARNING
index 0d70f3cc95d5043c9eff070dd288df92d21bf90b..ec33d7c4baf2c9839cbc3b60fb8735a5b131c31b 100644 (file)
@@ -4822,6 +4822,8 @@ count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
           of the access), set it here to the size of the string, including
           all internal and trailing nuls if the string has any.  */
        nbytes = nchars - offset;
+      else if (nchars - offset < nbytes)
+       return false;
 
       prep = TREE_STRING_POINTER (exp) + offset;
     }