Bug 55922 - brace initializing parent cause bogus virtual base constructor calls
Summary: brace initializing parent cause bogus virtual base constructor calls
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.7.2
: P3 normal
Target Milestone: 7.0
Assignee: Jason Merrill
URL:
Keywords: wrong-code
: 70818 80849 (view as bug list)
Depends on: 72457
Blocks:
  Show dependency treegraph
 
Reported: 2013-01-09 17:39 UTC by nicolas.cavallari
Modified: 2021-08-10 16:30 UTC (History)
3 users (show)

See Also:
Host: x86_64-unknown-linux-gnu
Target: x86_64-unknown-linux-gnu
Build:
Known to work: 7.1.0, 8.0.1
Known to fail: 4.9.2, 5.1.0, 6.0, 6.3.0
Last reconfirmed: 2018-02-19 00:00:00


Attachments
minimal program which does not work. (195 bytes, text/x-c++src)
2013-01-09 17:39 UTC, nicolas.cavallari
Details
same source with more outputs. (375 bytes, text/x-c++src)
2013-01-09 17:42 UTC, nicolas.cavallari
Details

Note You need to log in before you can comment on or make changes to this bug.
Description nicolas.cavallari 2013-01-09 17:39:47 UTC
Created attachment 29128 [details]
minimal program which does not work.

The attached minimal c++11 source compiles with g++ -std=c++11 minimal.c++, but the program does not run as expected (indicated by a non-zero exit value). Using clang works.

The same source with debug outputs shows that the virtual base constructor is called more than once upon initialization with bogus 'this' pointers. Not all classes agree on the offset to the virtual base. This causes silent member corruption (and ultimately crashes if some of the members are pointers).

Replacing brace initializers for B1 and A2 with C++03 parentheses initializers makes the problem go away.

Bug is also reproducible on trunk@195009 configured with ./configure --enable-languages=c,c++ --prefix=...
Comment 1 nicolas.cavallari 2013-01-09 17:42:47 UTC
Created attachment 29129 [details]
same source with more outputs.

Example output of what i have on my system with this attachment :

Base ctor is called at 0x7fffb7eeb474
Base ctor is called at 0x7fffb7eeb468
A1::Base is at 0x7fffb7eeb468
B1::Base is at 0x7fffb7eeb468
Base ctor is called at 0x7fffb7eeb470
A2::Base is at 0x7fffb7eeb470
C::Base is at 0x7fffb7eeb474
2 2 3


Standard output should read "1 2 3".
Comment 2 Jonathan Wakely 2015-06-25 10:16:15 UTC
bool called = false;

struct Base {
  Base() { if (called) throw 1; called = true; }
};

struct B1 : virtual Base {
  B1() { }
};

struct C : B1, virtual Base {
  C() :
#ifdef FIX
    B1()
#else
    B1{}
#endif
  { }
};

int main() {
  C c;
}
Comment 3 Jonathan Wakely 2016-04-27 09:55:12 UTC
*** Bug 70818 has been marked as a duplicate of this bug. ***
Comment 4 Martin Sebor 2016-07-07 17:13:37 UTC
I'm not sure how helpful or relevant this is at this point but according to my testing the wrong code seems to have been emitted since r142404 committed in the gcc 4.4.0 release cycle:

r142404 | jason | 2008-12-03 14:22:08 -0500 (Wed, 03 Dec 2008) | 6 lines

        PR c++/38380
        * decl.c (grokdeclarator): Only set DECL_NONCONVERTING_P
        on explicit constructors.
        * pt.c (tsubst_copy_and_build) [CONSTRUCTOR]: Propagate
        CONSTRUCTOR_IS_DIRECT_INIT.

Prior to that, GCC rejected the program with the following error:

error: converting to ‘const B1’ from initializer list would use explicit constructor ‘B1::B1()’
Comment 5 Jason Merrill 2016-07-24 02:56:57 UTC
Author: jason
Date: Sun Jul 24 02:56:22 2016
New Revision: 238688

URL: https://gcc.gnu.org/viewcvs?rev=238688&root=gcc&view=rev
Log:
	PR c++/55922 - list-value-initialization of base

	PR c++/63151
	* init.c (expand_aggr_init_1): Handle list-initialization from {}.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/initlist-base2.C
    trunk/gcc/testsuite/g++.dg/cpp0x/initlist-base3.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/init.c
Comment 6 Jason Merrill 2016-07-24 03:06:22 UTC
Author: jason
Date: Sun Jul 24 03:05:46 2016
New Revision: 238694

URL: https://gcc.gnu.org/viewcvs?rev=238694&root=gcc&view=rev
Log:
	PR c++/55922 - list-value-initialization of base

	PR c++/63151
	* init.c (expand_aggr_init_1): Handle list-initialization from {}.

Added:
    branches/gcc-6-branch/gcc/testsuite/g++.dg/cpp0x/initlist-base2.C
    branches/gcc-6-branch/gcc/testsuite/g++.dg/cpp0x/initlist-base3.C
Modified:
    branches/gcc-6-branch/gcc/cp/ChangeLog
    branches/gcc-6-branch/gcc/cp/init.c
Comment 7 Jason Merrill 2016-07-25 21:16:46 UTC
Fixed for 6.2/7 so far.
Comment 8 nicolas.cavallari 2016-09-16 10:06:59 UTC
While your minimal test case seems to be fixed, my test case still fails on GCC 6.2.0 (Debian):

The output is now:

Base ctor is called at 0x7fff79b27a14
A1::Base is at 0x7fff79b27a14
B1::Base is at 0x7fff79b27a14
Base ctor is called at 0x7fff79b27a10
A2::Base is at 0x7fff79b27a10
C::Base is at 0x7fff79b27a14
2 2 3


There is one less base constructor call, so we are getting there.
Comment 9 Daniel Boles 2017-05-21 20:32:33 UTC
*** Bug 80849 has been marked as a duplicate of this bug. ***
Comment 10 Daniel Boles 2017-05-21 20:41:36 UTC
*** Bug 80849 has been marked as a duplicate of this bug. ***
Comment 11 Daniel Boles 2017-05-21 20:43:48 UTC
This still occurs in 6.3.0

In the duplicate

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

I showed that whether or not this occurs can sometimes (I say because my results don't seem consistent with everyone else's) depend on the number of arguments that are given to (all of) the constructors.

I could not replicate the problem with my test case if the constructors were invoked with brace syntax and all had no or 1 argument, but I could when they had 2 or more arguments.
Comment 12 Jason Merrill 2017-09-18 18:34:23 UTC
Author: jason
Date: Mon Sep 18 18:33:52 2017
New Revision: 252937

URL: https://gcc.gnu.org/viewcvs?rev=252937&root=gcc&view=rev
Log:
	PR c++/55922 - list-value-initialization of base

	PR c++/63151
	* init.c (expand_aggr_init_1): Handle list-initialization from {}.

Added:
    branches/gcc-5-branch/gcc/testsuite/g++.dg/cpp0x/initlist-base2.C
    branches/gcc-5-branch/gcc/testsuite/g++.dg/cpp0x/initlist-base3.C
Modified:
    branches/gcc-5-branch/gcc/cp/ChangeLog
    branches/gcc-5-branch/gcc/cp/init.c
Comment 13 Jonathan Wakely 2018-02-19 15:33:14 UTC
This is fixed in GCC 7.1 and later, but not in the gcc-6 branch.
Comment 14 Jonathan Wakely 2018-02-19 18:41:05 UTC
The testcase in comment 1 originally made three calls to _ZN4BaseC2Ev until 
r238688 when it made two, and then only one call after r238689 (the fix for PR 66617).

So it looks like the reason it's still wrong on gcc-6-branch is that r238689 isn't on the branch.
Comment 15 Martin Liška 2018-11-19 12:54:15 UTC
Can the bug be marked as resolved?
Comment 16 Andrew Pinski 2021-08-10 16:30:59 UTC
Fixed so closing.