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

            Bug ID: 114051
           Summary: Incorrect out-of-bounds warning in loop that never
                    executes, due to failure to eliminate a dead branch
           Product: gcc
           Version: 13.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: fstromback at gmail dot com
  Target Milestone: ---

Created attachment 57493
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=57493&action=edit
Preprocessed version of bug.c, in case it helps.

When I compile the program below using: gcc -O3 bug.c

--------------
extern int puts(const char *);
#define CHAR_BIT 8

typedef unsigned long long ULongest;
#define MPS_WORD_WIDTH (sizeof(void *) * CHAR_BIT)

static void WriteULongest(ULongest w, unsigned base,
                                                unsigned width)
{
        static const char digit[16 + 1] = "0123456789ABCDEF";
    /* + 1 for terminator: unused, but prevents compiler warning */
        static const char pad = '0'; /* padding character */
        char buf[MPS_WORD_WIDTH + 1]; /* enough for binary, */
        /* plus one for terminator */
        unsigned i;

        /* Add digits to the buffer starting at the right-hand end, so that */
        /* the buffer forms a string representing the number.  A do...while */
        /* loop is used to ensure that at least one digit (zero) is written */
        /* when the number is zero. */
        i = MPS_WORD_WIDTH;
        buf[i] = '\0';
        do {
                --i;
                buf[i] = digit[w % base];
                w /= base;
        } while(w > 0);

        /* If the number is not as wide as the requested field, pad out the */
        /* buffer with zeros. */
        while(i > MPS_WORD_WIDTH - width) {
                --i;
                buf[i] = pad;
        }

        puts(&buf[i]);
}


int main(int argc, const char *argv[]) {
        (void)argv;
        WriteULongest((ULongest)argc, 16, 1); // Note: Occurs for width = 0 and
width = 1
        return 0;
}
--------------


I get the following warning:

----------------
In function 'WriteULongest',
    inlined from 'main' at bug.c:44:2:
bug.c:35:24: warning: '__builtin_memset' writing 4294967232 bytes into a region
of size 2 overflows the destination [-Wstringop-overflow=]
   35 |                 buf[i] = pad;
      |                 ~~~~~~~^~~~~
bug.c: In function 'main':
bug.c:15:14: note: at offset 63 into destination object 'buf' of size 65
   15 |         char buf[MPS_WORD_WIDTH + 1]; /* enough for binary, */
      |              ^~~
----------------

This happens when the last parameter (width) to the function WriteULongest is
known to be either zero or one (see comment in the file). By inspecting the
generated code (with -S), it seems like GCC transforms the second loop into a
call to memset guarded by an if-statement similarly to below:

if (i > 63) {
   memset(buf, '0', 4294967232);
}

The call to memset is indeed incorrect. However, GCC fails to consider that "i
> 63" is never true, since "i" is initialized to 64 and then always decreased
at least once in the previous loop. The call to memset could therefore be
removed entirely.



Output of gcc -v:

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 13.2.0-13'
--with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs
--enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr
--with-gcc-major-version-only --program-suffix=-13
--program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id
--libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix
--libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug
--enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new
--enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify
--enable-plugin --enable-default-pie --with-system-zlib
--enable-libphobos-checking=release --with-target-system-zlib=auto
--enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet
--with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32
--enable-multilib --with-tune=generic
--enable-offload-targets=nvptx-none=/build/reproducible-path/gcc-13-13.2.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/reproducible-path/gcc-13-13.2.0/debian/tmp-gcn/usr
--enable-offload-defaulted --without-cuda-driver --enable-checking=release
--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 13.2.0 (Debian 13.2.0-13)

Reply via email to