gcc 4.2 miscompilation with -O2 -fno-omit-frame-pointer on amd64

Gleb Kurtsou gleb.kurtsou at gmail.com
Sat Dec 10 01:21:25 UTC 2011


Please find test case and test results attached. (gcc-test1.shar.txt)

The long story short: only gcc-4.2 is affected, gcc 3.4, 4.4 and 4.6 are
ok. clang is ok. (test-cc.txt)

Nearly all of the workarounds I used in original test doesn't work in
this test case (see #ifdef BAD_FIX in sources).

gcc 4.2 fails even with -O1, it has nothing to do with
-fno-omit-frame-pointer, finline-functions, etc. (test-cflags.txt)

Compile with -DFIX1 to work around problem (replace struct assignment
with memcpy):
% make test XFLAGS="-O2 -DFIX1"
rm -f gcc-test1 src1.o src2.o src3.o
cc -O2 -DFIX1 -g -std=gnu99   -c src1.c
cc -O2 -DFIX1 -g -std=gnu99   -c src2.c
cc -O2 -DFIX1 -g -std=gnu99   -c src3.c
cc -O2 -DFIX1 -g -std=gnu99    -o gcc-test1 src1.o src2.o src3.o 
/home/gleb/projects/gcc-test1/gcc-test1
ok

Happy hacking!
-------------- next part --------------
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	Makefile
#	array.h
#	debug.h
#	hdr1.h
#	src1.c
#	src2.c
#	src3.c
#
echo x - Makefile
sed 's/^X//' >Makefile << 'b67911656ef5d18c4ae36cb6741b7965'
XPROG=   gcc-test1
XSRCS=	src1.c src2.c src3.c hdr1.h
XNO_MAN=
X
XXFLAGS?=-O2 -fno-omit-frame-pointer
X
X#WARNS=6
X#NO_WERROR=
X
XSSP_CFLAGS=
XDEBUG_FLAGS= -g
XCSTD= gnu99
X
XCFLAGS= ${XFLAGS}
X
X.PHONY: test
Xtest: clean ${PROG}
X	${.OBJDIR}/${PROG}
X
X.include <bsd.prog.mk>
b67911656ef5d18c4ae36cb6741b7965
echo x - array.h
sed 's/^X//' >array.h << '3ff8e27b821109f0551768c5e1b6bc0d'
X#include "debug.h"
X
X#define ARRAY_HEAD(name, type, capacity)				\
X	struct name {							\
X		size_t arr_count;					\
X		struct type arr_items[capacity];			\
X	}
X
X#define ARRAY_INIT(head) do {						\
X	(head)->arr_count = 0;						\
X} while (0)
X
X#define ARRAY_CAPACITY(head)						\
X	(sizeof((head)->arr_items) / sizeof((head)->arr_items[0]))
X
X#define ARRAY_COUNT(head)		(head)->arr_count
X
X#ifdef FIX1
X
X#define ARRAY_INSERT_TAIL(head, elm) do {				\
X	ASSERT(ARRAY_COUNT((head)) < ARRAY_CAPACITY((head)));		\
X	memcpy(&(head)->arr_items[(head)->arr_count++], &(elm), sizeof(elm)); \
X} while (0)
X
X#else
X
X#define ARRAY_INSERT_TAIL(head, elm) do {				\
X	ASSERT(ARRAY_COUNT((head)) < ARRAY_CAPACITY((head)));		\
X	(head)->arr_items[(head)->arr_count++] = (elm);			\
X} while (0)
X
X#endif
X
X#define ARRAY_FOREACH(var, head)					\
X	for ((var) = &(head)->arr_items[0];				\
X		(var) < &(head)->arr_items[0] + (head)->arr_count;	\
X		(var)++)
3ff8e27b821109f0551768c5e1b6bc0d
echo x - debug.h
sed 's/^X//' >debug.h << '0483bb2079adc3936e07b79b224930aa'
X#ifndef XXX_DEBUG_H
X#define XXX_DEBUG_H
X
X#include <stdarg.h>
X
X#define ASSERT(cond)							\
X	(__predict_false(cond) ? (void)0 :				\
X	    debug_assert(#cond, __FILE__, __LINE__, __func__))
X
Xvoid debug_assert(const char *msg, const char *file, int line,
X    const char *func);
X
X#endif
0483bb2079adc3936e07b79b224930aa
echo x - hdr1.h
sed 's/^X//' >hdr1.h << '023696bd679b9970bb745000978348c8'
X#include <stdbool.h>
X
X#include "array.h"
X#include "debug.h"
X
Xtypedef union {
X	struct {
X		bool	flag1:1;
X		bool	flag2:1;
X		bool	flag3:1;
X		bool	flag4:1;
X		bool	flag5:1;
X		bool	flag6:1;
X		bool	flag7:1;
X		bool	flag8:1;
X		bool	flag9:1;
X		bool	flag10:1;
X	};
X	uint32_t	bits;
X} xflags_t;
X
Xstruct session {
X	xflags_t flags;
X	struct sockaddr_in	addr;
X};
X
Xstruct dummy1 {
X	int a, b, c;
X	void *ptr;
X};
X
XARRAY_HEAD(addr_list, sockaddr_in, 2);
X
Xstruct addr_list;
X
Xvoid test_fail(void *arg1, void *arg2,
X    void *arg3, const void *arg4,
X    const struct addr_list *addr_list,
X    const void *arg5);
X
Xbool test_run(struct session *sess);
023696bd679b9970bb745000978348c8
echo x - src1.c
sed 's/^X//' >src1.c << 'd76eceed15fcbc6c2cf5da795270acb3'
X#include <sys/param.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X
X#include "hdr1.h"
X
Xstatic void test_set_dummy(struct dummy1 *arg1, void *arg2);
X
Xbool
Xtest_run(struct session *sess)
X{
X	struct dummy1 d1 __unused;
X	struct addr_list tmp_addr_list;
X	struct sockaddr_in tmp_addr;
X	bool rv = true;
X
X#ifdef BAD_FIX
X	// Removing assertions fixes original test case
X	ASSERT(sess->flags.flag5);
X	ASSERT(sess->flags.flag4);
X	ASSERT(sess->flags.flag7);
X	ASSERT(sess->flags.flag9);
X#endif
X
X	// Replacing assignment with memcpy fixes original test case
X	tmp_addr = sess->addr;
X	tmp_addr.sin_port = 0;
X	ARRAY_INIT(&tmp_addr_list);
X	ARRAY_INSERT_TAIL(&tmp_addr_list, tmp_addr);
X
X#ifdef BAD_FIX
X	// Removing function call fixes original test case
X	test_set_dummy(&d1, sess);
X#endif
X
X	test_fail(NULL, NULL,
X	     NULL, NULL, &tmp_addr_list, NULL);
X
X	return rv;
X}
X
Xstruct dummy1 d1_template = {
X	.a = 1,
X	.b = 2,
X};
X
Xstatic void
Xtest_set_dummy(struct dummy1 *arg1, void *arg2 __unused)
X{
X	*arg1 = d1_template;
X}
d76eceed15fcbc6c2cf5da795270acb3
echo x - src2.c
sed 's/^X//' >src2.c << '84fb2eee7bfbf3aefc26348a2ac4dc34'
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X
X#include "hdr1.h"
X
Xvoid
Xtest_fail(void *arg1 __unused, void *arg2 __unused,
X    void *arg3 __unused, const void *arg4 __unused,
X    const struct addr_list *addr_list,
X    const void *arg6 __unused)
X{
X	const struct sockaddr_in *addr;
X
X	ARRAY_FOREACH(addr, addr_list) {
X		ASSERT(addr->sin_addr.s_addr == ntohl(INADDR_ANY));
X	}
X}
84fb2eee7bfbf3aefc26348a2ac4dc34
echo x - src3.c
sed 's/^X//' >src3.c << 'e773224103ed63e54dbf72915ff448a8'
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X
X#include <stdbool.h>
X#include <stdio.h>
X#include <stdlib.h>
X
X#include "hdr1.h"
X
Xint
Xmain(int argc __unused, char **argv __unused)
X{
X	struct session *sess;
X
X	sess = calloc(sizeof(*sess), 1);
X	sess->flags.flag1 = true;
X	sess->flags.flag4 = true;
X	sess->flags.flag5 = true;
X	sess->flags.flag6 = true;
X	sess->flags.flag7 = true;
X	sess->flags.flag9 = true;
X
X	sess->addr.sin_addr.s_addr = ntohl(INADDR_ANY);
X
X	test_run(sess);
X
X	puts("ok");
X
X	return 0;
X}
X
Xvoid
Xdebug_assert(const char *msg, const char *file, int line, const char *func)
X{
X	if (func == NULL)
X		fprintf(stderr, "%s:%d: Assertion failed: %s\n",
X		    file, line, msg);
X	else
X		fprintf(stderr, "%s:%d:%s: Assertion failed: %s\n",
X		    file, line, func, msg);
X	abort();
X}
e773224103ed63e54dbf72915ff448a8
exit

-------------- next part --------------
% for CC in cc gcc42 gcc34 gcc44 gcc46 clang; do ${CC} -v; make test CC=${CC}; done
Using built-in specs.
Target: amd64-undermydesk-freebsd
Configured with: FreeBSD/amd64 system compiler
Thread model: posix
gcc version 4.2.1 20070831 patched [FreeBSD]
rm -f gcc-test1 src1.o src2.o src3.o
cc -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src1.c
cc -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src2.c
cc -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src3.c
cc -O2 -fno-omit-frame-pointer -g -std=gnu99    -o gcc-test1 src1.o src2.o src3.o 
/home/gleb/projects/gcc-test1/gcc-test1
src2.c:16:test_fail: Assertion failed: addr->sin_addr.s_addr == ntohl(INADDR_ANY)
*** Signal 6

Stop in /home/gleb/projects/gcc-test1.
zsh: exit 1     make test CC=${CC}
Using built-in specs.
Target: x86_64-portbld-freebsd9.0
Configured with: ./../gcc-4.2-20090325/configure --disable-nls --libdir=/usr/local/lib/gcc42 --libexecdir=/usr/local/libexec/gcc42 --program-suffix=42 --with-as=/usr/bin/as --with-gmp=/usr/local --with-gxx-include-dir=/usr/local/lib/gcc42/include/c++/ --with-ld=/usr/bin/ld --with-libiconv-prefix=/usr/local --with-system-zlib --prefix=/usr/local --mandir=/usr/local/man --infodir=/usr/local/info/gcc42 x86_64-portbld-freebsd9.0
Thread model: posix
gcc version 4.2.5 20090325 (prerelease) [FreeBSD Ports Collection]
rm -f gcc-test1 src1.o src2.o src3.o
gcc42 -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src1.c
gcc42 -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src2.c
gcc42 -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src3.c
gcc42 -O2 -fno-omit-frame-pointer -g -std=gnu99    -o gcc-test1 src1.o src2.o src3.o 
/home/gleb/projects/gcc-test1/gcc-test1
src2.c:16:test_fail: Assertion failed: addr->sin_addr.s_addr == ntohl(INADDR_ANY)
*** Signal 6

Stop in /home/gleb/projects/gcc-test1.
zsh: exit 1     make test CC=${CC}
Reading specs from /usr/local/lib/gcc/x86_64-portbld-freebsd9.0/3.4.6/gcc/x86_64-portbld-freebsd9.0/3.4.6/specs
Configured with: ./..//gcc-3.4.6/configure --disable-nls --with-system-zlib --with-libiconv-prefix=/usr/local --program-suffix=34 --libdir=/usr/local/lib/gcc/x86_64-portbld-freebsd9.0/3.4.6 --with-gxx-include-dir=/usr/local/lib/gcc/x86_64-portbld-freebsd9.0/3.4.6/include/c++/ --prefix=/usr/local --mandir=/usr/local/man --infodir=/usr/local/info/gcc34 x86_64-portbld-freebsd9.0
Thread model: posix
gcc version 3.4.6 [FreeBSD]
rm -f gcc-test1 src1.o src2.o src3.o
gcc34 -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src1.c
gcc34 -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src2.c
gcc34 -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src3.c
gcc34 -O2 -fno-omit-frame-pointer -g -std=gnu99    -o gcc-test1 src1.o src2.o src3.o 
/usr/bin/ld: error in /usr/local/lib/gcc/x86_64-portbld-freebsd9.0/3.4.6/gcc/x86_64-portbld-freebsd9.0/3.4.6/crtend.o(.eh_frame); no .eh_frame_hdr table will be created.
/home/gleb/projects/gcc-test1/gcc-test1
ok
Using built-in specs.
Target: x86_64-portbld-freebsd9.0
Configured with: ./../gcc-4.4-20111108/configure --disable-nls --enable-languages=c,c++,fortran --libdir=/usr/local/lib/gcc44 --libexecdir=/usr/local/libexec/gcc44 --program-suffix=44 --with-as=/usr/local/bin/as --with-gmp=/usr/local --with-gxx-include-dir=/usr/local/lib/gcc44/include/c++/ --with-ld=/usr/local/bin/ld --with-libiconv-prefix=/usr/local --with-pkgversion='FreeBSD Ports Collection' --with-system-zlib --prefix=/usr/local --mandir=/usr/local/man --infodir=/usr/local/info/gcc44 --build=x86_64-portbld-freebsd9.0
Thread model: posix
gcc version 4.4.7 20111108 (prerelease) (FreeBSD Ports Collection) 
rm -f gcc-test1 src1.o src2.o src3.o
gcc44 -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src1.c
gcc44 -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src2.c
gcc44 -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src3.c
gcc44 -O2 -fno-omit-frame-pointer -g -std=gnu99    -o gcc-test1 src1.o src2.o src3.o 
/home/gleb/projects/gcc-test1/gcc-test1
ok
Using built-in specs.
COLLECT_GCC=gcc46
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc46/gcc/x86_64-portbld-freebsd9.0/4.6.2/lto-wrapper
Target: x86_64-portbld-freebsd9.0
Configured with: ./../gcc-4.6.2/configure --disable-nls --enable-languages=c,c++,fortran --libdir=/usr/local/lib/gcc46 --libexecdir=/usr/local/libexec/gcc46 --program-suffix=46 --with-as=/usr/local/bin/as --with-gmp=/usr/local --with-gxx-include-dir=/usr/local/lib/gcc46/include/c++/ --with-ld=/usr/local/bin/ld --with-libiconv-prefix=/usr/local --with-pkgversion='FreeBSD Ports Collection' --with-system-zlib --enable-languages=c,c++,fortran,java --prefix=/usr/local --mandir=/usr/local/man --infodir=/usr/local/info/gcc46 --build=x86_64-portbld-freebsd9.0
Thread model: posix
gcc version 4.6.2 (FreeBSD Ports Collection) 
rm -f gcc-test1 src1.o src2.o src3.o
gcc46 -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src1.c
gcc46 -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src2.c
gcc46 -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src3.c
gcc46 -O2 -fno-omit-frame-pointer -g -std=gnu99    -o gcc-test1 src1.o src2.o src3.o 
/home/gleb/projects/gcc-test1/gcc-test1
ok
clang version 3.0 (trunk)
Target: amd64-portbld-freebsd9.0
Thread model: posix
rm -f gcc-test1 src1.o src2.o src3.o
clang -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src1.c
clang -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src2.c
clang -O2 -fno-omit-frame-pointer -g -std=gnu99   -c src3.c
clang -O2 -fno-omit-frame-pointer -g -std=gnu99    -o gcc-test1 src1.o src2.o src3.o 
clang: warning: argument unused during compilation: '-g'
clang: warning: argument unused during compilation: '-std=gnu99'
/home/gleb/projects/gcc-test1/gcc-test1
ok
~/projects/gcc-test1 % 

-------------- next part --------------
% for XFLAGS in -O0 -O1 -O2 -O3; do make test XFLAGS=${XFLAGS}; done               
rm -f gcc-test1 src1.o src2.o src3.o
cc -O0 -g -std=gnu99   -c src1.c
cc -O0 -g -std=gnu99   -c src2.c
cc -O0 -g -std=gnu99   -c src3.c
cc -O0 -g -std=gnu99    -o gcc-test1 src1.o src2.o src3.o 
/home/gleb/projects/gcc-test1/gcc-test1
ok
rm -f gcc-test1 src1.o src2.o src3.o
cc -O1 -g -std=gnu99   -c src1.c
cc -O1 -g -std=gnu99   -c src2.c
cc -O1 -g -std=gnu99   -c src3.c
cc -O1 -g -std=gnu99    -o gcc-test1 src1.o src2.o src3.o 
/home/gleb/projects/gcc-test1/gcc-test1
src2.c:16:test_fail: Assertion failed: addr->sin_addr.s_addr == ntohl(INADDR_ANY)
*** Signal 6

Stop in /home/gleb/projects/gcc-test1.
zsh: exit 1     make test XFLAGS=${XFLAGS}
rm -f gcc-test1 src1.o src2.o src3.o
cc -O2 -g -std=gnu99   -c src1.c
cc -O2 -g -std=gnu99   -c src2.c
cc -O2 -g -std=gnu99   -c src3.c
cc -O2 -g -std=gnu99    -o gcc-test1 src1.o src2.o src3.o 
/home/gleb/projects/gcc-test1/gcc-test1
src2.c:16:test_fail: Assertion failed: addr->sin_addr.s_addr == ntohl(INADDR_ANY)
*** Signal 6

Stop in /home/gleb/projects/gcc-test1.
zsh: exit 1     make test XFLAGS=${XFLAGS}
rm -f gcc-test1 src1.o src2.o src3.o
cc -O3 -g -std=gnu99   -c src1.c
cc -O3 -g -std=gnu99   -c src2.c
cc -O3 -g -std=gnu99   -c src3.c
cc -O3 -g -std=gnu99    -o gcc-test1 src1.o src2.o src3.o 
/home/gleb/projects/gcc-test1/gcc-test1
src2.c:16:test_fail: Assertion failed: addr->sin_addr.s_addr == ntohl(INADDR_ANY)
*** Signal 6


More information about the freebsd-hackers mailing list