Bug 36960 - Reference variable in virtually inherited base corrupted under optimization
Reference variable in virtually inherited base corrupted under optimization
Status: RESOLVED WONTFIX
Product: gcc
Classification: Unclassified
Component: c++
4.2.2
: P3 normal
: ---
Assigned To: Not yet assigned to anyone
: alias
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2008-07-28 23:57 UTC by Raymond Russell
Modified: 2010-07-13 09:41 UTC (History)
4 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Raymond Russell 2008-07-28 23:57:37 UTC
Apologies if this is a duplicate:  I searched existing reports and found tons of hits on "virtual inheritance" and "reference", but couldn't find anything like this.  The following program illustrates the problem:

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

struct Lower {
	const int&	ref;

	Lower(const int& ref) : ref(ref) { }
};


struct Middle : public virtual Lower {

	Middle(const int& ref) : Lower(ref) { }
};


struct Upper : public Middle {

	Upper(const int& ref) : Lower(ref), Middle(ref) { }

	int	get()
	{
		return ref;
	}
};


int	main()
{
	int i = 0;
	Upper upper(i);

	return upper.get();
}


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Compiling this using 4.2.2 or 4.2.3 with -O2 or higher causes the resulting binary to return a non-zero value;  3.4.2 produces a bug-free binary.  I've seen the same effect in more complex code, where gdb gives an obviously wrong address for the "ref" member.  Dropping to -O fixes the problem, as do several other changes:

* Making "ref" an int (as opposed to an int&)
* Making Middle inherit non-virtually from Lower
* Accessing "ref" from Middle instead of Upper

The constness of the reference has no effect.


Issued command-line:
    g++ -Wall -W -Wundef -Wpointer-arith -g -O2 VirtuallyInheritedReference.cpp

Full output from running with "-v --save-temps" is as follows:
    g++ -v -save-temps -Wall -W -Wundef -Wpointer-arith -g -O2 -c -o /dev/null VirtuallyInheritedReference.cpp

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: /mnt/taw/usr/Taw/tmp/gcc-4.2.2/configure --prefix=/usr --disable-nls --libexecdir=/usr/lib --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-languages=c,c++ --disable-bootstrap
Thread model: posix
gcc version 4.2.2
 /usr/lib/gcc/i686-pc-linux-gnu/4.2.2/cc1plus -E -quiet -v -D_GNU_SOURCE VirtuallyInheritedReference.cpp -mtune=generic -Wall -W -Wundef -Wpointer-arith -fworking-directory -O2 -fpch-preprocess -o VirtuallyInheritedReference.ii
ignoring nonexistent directory "/usr/lib/gcc/i686-pc-linux-gnu/4.2.2/../../../../i686-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/i686-pc-linux-gnu/4.2.2/../../../../include/c++/4.2.2
 /usr/lib/gcc/i686-pc-linux-gnu/4.2.2/../../../../include/c++/4.2.2/i686-pc-linux-gnu
 /usr/lib/gcc/i686-pc-linux-gnu/4.2.2/../../../../include/c++/4.2.2/backward
 /usr/local/include
 /usr/lib/gcc/i686-pc-linux-gnu/4.2.2/include
 /usr/include
End of search list.
 /usr/lib/gcc/i686-pc-linux-gnu/4.2.2/cc1plus -fpreprocessed VirtuallyInheritedReference.ii -quiet -dumpbase VirtuallyInheritedReference.cpp -mtune=generic -auxbase-strip /dev/null -g -O2 -Wall -W -Wundef -Wpointer-arith -version -o VirtuallyInheritedReference.s
GNU C++ version 4.2.2 (i686-pc-linux-gnu)
        compiled by GNU C version 4.2.2.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 6ba594205d388e98f3b46dee442d61ac
 as -V -Qy -o /dev/null VirtuallyInheritedReference.s
GNU assembler version 2.18 (i686-pc-linux-gnu) using BFD version (GNU Binutils) 2.18
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>



Contents of VirtuallyInheritedReference.ii:

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
# 1 "VirtuallyInheritedReference.cpp"
# 1 "/home/raymond/src/C++/gcc-bugs//"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "VirtuallyInheritedReference.cpp"

struct Lower {
 int& ref;

 virtual ~Lower() { }

 Lower(int& ref) : ref(ref) { }
};


struct Middle : public virtual Lower {

 Middle(int& ref) : Lower(ref) { }
};


struct Upper : public Middle {

 Upper(int& ref) : Lower(ref), Middle(ref) { }

 int get()
 {
  return ref;
 }
};


int main()
{
 int i = 0;
 Upper upper(i);

 return upper.get();
}

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Comment 1 Andrew Pinski 2008-07-29 00:01:40 UTC
  i = 0;
  upper.D.2127.ref = &i;
  upper.D.2125._vptr$Middle = &_ZTV5Upper + 12;
  return *((struct Lower *) &upper + (long unsigned int) *(int *) &_ZTV5Upper)->ref;

This works on the trunk correctly.
Comment 2 Andrew Pinski 2008-07-29 00:02:36 UTC
Likewise for 4.3.0.
Comment 3 Steven Bosscher 2010-07-13 09:41:36 UTC
Works with GCC 4.3, 4.4, 4.5, and trunk.

GCC 4.2 is no longer maintained, so this bug will not be fixed.

Richi, perhaps you can use the test case, put it in the test suite?
Comment 4 Richard Biener 2010-07-13 13:31:38 UTC
Subject: Bug 36960

Author: rguenth
Date: Tue Jul 13 13:31:26 2010
New Revision: 162141

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=162141
Log:
2010-07-13  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/36960
	* g++.dg/torture/pr36960.C: New testcase.

Added:
    trunk/gcc/testsuite/g++.dg/torture/pr36960.C
Modified:
    trunk/gcc/testsuite/ChangeLog