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

            Bug ID: 87167
           Summary: strlen of stack-allocated zero-length array
                    misoptimized in GCC 8
           Product: gcc
           Version: 8.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: matti.niemenmaa+gccbugs at iki dot fi
  Target Milestone: ---

Created attachment 44636
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44636&action=edit
Preprocessed source

Unpreprocessed source code for illustration, reduced from UADE 2.13 (Unix Amiga
Delitracker Emulator):


#include <stdio.h>
#include <string.h>

struct uade_msg {
  int x;
  char data[0];
} __attribute__((packed));

int main(void) {
  char commandbuf[4096] = {0};
  struct uade_msg *um = (struct uade_msg *)commandbuf;
  strcpy(um->data, "foobar");
  printf("%s has strlen %zu\n", um->data, strlen((const char *)um->data));
  printf("%s has strlen %zu\n", um->data, strlen((const char *)um->data));
}


When compiled with -O2 -fno-strict-aliasing on GCC 8.2.0, the output of the
resulting program on my x86-64 machine is:

foobar has strlen 6
foobar has strlen 0

GCC 7.3.1 and 5.4.1 show a strlen of 6 on both output lines. (As does clang
6.0.1, for what it's worth.)

Looking at a snippet of the assembly, around the printf calls:

        movl    $6, %edx
        leaq    .LC0(%rip), %rdi
        movl    $1651470182, 4(%rsp)
        call    printf@PLT
        xorl    %edx, %edx
        xorl    %eax, %eax
        movq    %rbx, %rsi
        leaq    .LC0(%rip), %rdi
        call    printf@PLT

It looks like GCC 8.2.0 has optimized away both strlen calls, but replaced each
with a different value. Based on a cursory inspection, GCC 7.3.1 and 5.4.1
optimize away the first strlen call and inline the second (and clang 6.0.1
doesn't do anything to the first but re-uses the result instead of doing
another call).

Replacing the `char data[0]` with `char data[]` seems to cause GCC 8.2.0 to
behave the same way as 7.3.1 and 5.4.1, resulting in an output of 6 on both
lines. Using calloc instead of the stack allocation does the same.

It's been a while since I had to worry about the aliasing rules in C so I'm not
entirely sure whether this is code is invalid or not, but regardless, I would
expect to always see a result of 6 here with -fno-strict-aliasing.


Full output from gcc uade.c -O2 -fno-strict-aliasing -Wall -Wextra -v
-save-temps:

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib
--libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info
--with-bugurl=https://bugs.archlinux.org/
--enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared
--enable-threads=posix --enable-libmpx --with-system-zlib --with-isl
--enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu
--disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object
--enable-linker-build-id --enable-lto --enable-plugin
--enable-install-libiberty --with-linker-hash-style=gnu
--enable-gnu-indirect-function --enable-multilib --disable-werror
--enable-checking=release --enable-default-pie --enable-default-ssp
--enable-cet=auto
Thread model: posix
gcc version 8.2.0 (GCC)
COLLECT_GCC_OPTIONS='-O2' '-fno-strict-aliasing' '-Wall' '-Wextra' '-v'
'-save-temps' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/cc1 -E -quiet -v uade.c -mtune=generic
-march=x86-64 -Wall -Wextra -fno-strict-aliasing -O2 -fpch-preprocess -o uade.i
ignoring nonexistent directory
"/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../x86_64-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/include
 /usr/local/include
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/include-fixed
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-O2' '-fno-strict-aliasing' '-Wall' '-Wextra' '-v'
'-save-temps' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/cc1 -fpreprocessed uade.i -quiet
-dumpbase uade.c -mtune=generic -march=x86-64 -auxbase uade -O2 -Wall -Wextra
-version -fno-strict-aliasing -o uade.s
GNU C17 (GCC) version 8.2.0 (x86_64-pc-linux-gnu)
        compiled by GNU C version 8.2.0, GMP version 6.1.2, MPFR version 4.0.1,
MPC version 1.1.0, isl version isl-0.19-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
GNU C17 (GCC) version 8.2.0 (x86_64-pc-linux-gnu)
        compiled by GNU C version 8.2.0, GMP version 6.1.2, MPFR version 4.0.1,
MPC version 1.1.0, isl version isl-0.19-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 374c644ab4db4fa02e30fa5669d43e86
COLLECT_GCC_OPTIONS='-O2' '-fno-strict-aliasing' '-Wall' '-Wextra' '-v'
'-save-temps' '-mtune=generic' '-march=x86-64'
 as -v --64 -o uade.o uade.s
GNU assembler version 2.31.1 (x86_64-pc-linux-gnu) using BFD version (GNU
Binutils) 2.31.1
COMPILER_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/:/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/:/usr/lib/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/:/usr/lib/gcc/x86_64-pc-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/:/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-O2' '-fno-strict-aliasing' '-Wall' '-Wextra' '-v'
'-save-temps' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/collect2 -plugin
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/liblto_plugin.so
-plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/lto-wrapper
-plugin-opt=-fresolution=uade.res -plugin-opt=-pass-through=-lgcc
-plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc
-plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id
--eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker
/lib64/ld-linux-x86-64.so.2 -pie
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../lib/Scrt1.o
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../lib/crti.o
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/crtbeginS.o
-L/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0
-L/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../lib -L/lib/../lib
-L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../.. uade.o
-lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s
--no-as-needed /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/crtendS.o
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../lib/crtn.o
COLLECT_GCC_OPTIONS='-O2' '-fno-strict-aliasing' '-Wall' '-Wextra' '-v'
'-save-temps' '-mtune=generic' '-march=x86-64'

Reply via email to