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'