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

            Bug ID: 128591
           Summary: fold_const_call folds strstr(s, "") to s during early
                    CCP without calling check_nul_terminated_array,
                    silently suppressing -Wstringop-overread on
                    non-NUL-terminated arrays
           Product: gcc
           Version: 16.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: 220245569 at seu dot edu.cn
                CC: 220255623 at seu dot edu.cn, jianhao.xu at seu dot edu.cn
  Target Milestone: ---
            Target: *-*-*

Reproducer
----------
$ cat trigger.c
static const char a[3] = "abc";

const char *probe_empty_needle(void) {
    return __builtin_strstr(a, "");
}

const char *control_nonempty_needle(void) {
    return __builtin_strstr(a, "z");
}

Compile command / flags:
podman exec defuzz-toolchain-daemon /opt/gcc16/bin/x86_64-linux-gnu-gcc -O2
-Wall -Wstringop-overread -S -o /dev/null /tmp/t1.c

Observed output (GCC 16.2.0):
<stdin>: In function 'control_nonempty_needle':
<stdin>:8:12: warning: '__builtin_strstr' argument missing terminating nul
[-Wstringop-overread]
<stdin>:1:19: note: referenced argument declared here
(Zero warning emitted for probe_empty_needle)

Expected behavior:
strstr(a, "") on a statically known non-NUL-terminated char array a[3] = "abc"
must either defer folding to gimple_fold_builtin_strstr (when c_getstr(arg0)
returns NULL) or emit -Wstringop-overread just like strstr(a, "z") and
strlen(a).

Root cause
----------
Source location: gcc/fold-const-call.cc:1864-1877 (fold_const_call
CFN_BUILT_IN_STRSTR) vs gcc/gimple-fold.cc:2306-2310
(gimple_fold_builtin_strstr)

gimple_fold_builtin_strstr (gcc/gimple-fold.cc:2306-2310) explicitly calls
check_nul_terminated_array (stmt, haystack) before folding an empty needle
(q[0] == '\0') to return haystack, ensuring -Wstringop-overread is emitted if
haystack is a non-NUL-terminated const array. However, when both haystack and
needle are constant addresses/strings (e.g., static const char a[3] = "abc";
strstr(a, "")), gimple_fold_stmt_to_constant_1 invokes fold_const_call
(gcc/fold-const-call.cc:1864-1877) during early CCP (ccp1) before
gimple_fold_builtin_strstr is reached. In fold_const_call, case
CFN_BUILT_IN_STRSTR checks if (s2[0] == '\0') and immediately returns
build_fold_addr_expr (arg0) without checking whether s1 is NUL-terminated and
without calling check_nul_terminated_array, erasing the call in ccp1 with zero
warning.

Impact:
False negative in -Wstringop-overread when non-NUL-terminated constant
character arrays are passed to strstr with an empty needle.

Suggested Fix
-------------
In gcc/fold-const-call.cc:1867 (case CFN_BUILT_IN_STRSTR), require (s1 =
c_getstr (arg0)) != NULL before folding s2[0] == '\0' to build_fold_addr_expr
(arg0), so non-NUL-terminated arrays fall through to gimple_fold_builtin_strstr
where check_nul_terminated_array diagnoses the overread.

Reply via email to