[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#764220: gcc incorrectly optimizes away parameter initialization



Package: gcc-4.6
Version: 4.6.3-14

This bug occurs on two gcc versions I tried on Debian Wheezy 7.6 x86:

g++-4.6 (Debian 4.6.3-14) 4.6.3
g++ (Debian 4.7.2-5) 4.7.2

and one version that I tried on Debian Jessie/Sid amd64:

gcc (Debian 4.9.1-15) 4.9.1
g++ (Debian 4.9.1-15) 4.9.1

I did not try other gcc versions. I would not be surprised if this bug is present in all gcc 4.x versions, or in all gcc versions that accept this code.

When my test program is compiled with

$ g++ -c test.C

the generated machine code looks sensible.
When it is compiled with

$ g++ -O -c test.C

the output will be too short, and there are no references to the external variable g. You can verify this with

$ nm test.o
00000000 T _Z12test_gcc_bugj
	 U _Z3fooRK1c

$ objdump -d test.o

sql/gcc-bug.o:     file format elf32-i386


Disassembly of section .text:

00000000 <_Z12test_gcc_bugj>:
  0:   83 ec 2c                sub    $0x2c,%esp
  3:   8d 44 24 1c             lea    0x1c(%esp),%eax
  7:   89 04 24                mov    %eax,(%esp)
  a:   e8 fc ff ff ff          call   b <_Z12test_gcc_bugj+0xb>
  f:   83 c4 2c                add    $0x2c,%esp
 12:   c3                      ret

I have prepared both C and C++ versions of this test program:

cat > test.c << EOF
struct c {
 unsigned a;
};

extern struct c g;

bool foo(const struct c* d) __attribute__((pure));

inline
const struct c*
bar(unsigned f)
{
 struct c d {g.a};
 return f ? &d : &g;
}

bool
test_gcc_bug(unsigned f)
{
 return foo(bar(f));
}
EOF

cat > test.C << EOF
class c {
public:
 c(unsigned b) : a(b) {}
 unsigned a;
};

extern c g;

bool foo(const c& d) __attribute__((const));

inline
const c
bar(unsigned f)
{
 return f ? c(g.a) : g;
}

bool
test_gcc_bug(unsigned f)
{
 return foo(bar(f));
}
EOF

When the __attribute__((pure)) or __attribute__((const)) is removed, all code will be emitted properly.

In the C++ version, I guess it is borderline if the __attribute__((const)) should be allowed. If the function accesses the memory pointed to by the reference, does that count as 'global memory', violating the 'const' attribute? If yes, then __attribute__((const)) should probably emit a warning when the function is taking references or pointers as parameters. Anyway, incorrect code is being emitted also for __attribute__((pure)).

This bug broke the MySQL 5.7.5 x86 build on Debian 7.6. The bug would not manifest itself when using gcc 4.6 on that platform, but that was only luck: gcc 4.6 would inline the problematic function call, while gcc 4.7 would inline it on this platform. The problematic code is this call in storage/innobase/btr/btr0pcur.cc, function btr_cur_pessimistic_insert():

	if (page_zip_rec_needs_ext(rec_get_converted_size(index, entry, n_ext),
				   dict_table_is_comp(index->table),
				   dtuple_get_n_fields(entry),
dict_table_page_size(index->table))) The function page_zip_rec_needs_ext() corresponds to "foo" in my test programs. It is declared as __attribute__((const)). The initialization of the object that is returned by dict_table_page_size() was omitted. That would be page_size_t in the MySQL source code, and "class c" or "struct c" in my test programs above. Space for the object was allocated from the stack, but there was no code emitted for initializing the object before page_zip_rec_needs_ext() was invoked.

With best regards,

	Marko Makela
	Senior Principal Software Engineer
	InnoDB Group, MySQL Server, Oracle Corporation


Reply to: