Bug 593124 - g++44 problem - crashes in dynamic cast runtime code
g++44 problem - crashes in dynamic cast runtime code
Status: CLOSED NOTABUG
Product: Red Hat Enterprise Linux 5
Classification: Red Hat
Component: gcc44 (Show other bugs)
5.5
All Linux
high Severity high
: rc
: ---
Assigned To: Jakub Jelinek
qe-baseos-tools
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2010-05-17 17:21 EDT by Alan Matsuoka
Modified: 2011-05-13 08:57 EDT (History)
2 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2010-05-31 09:39:35 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)
test.cpp (1.69 KB, text/x-c++src)
2010-05-17 17:22 EDT, Alan Matsuoka
no flags Details

  None (edit)
Description Alan Matsuoka 2010-05-17 17:21:41 EDT
Description of problem:
The attached the testcase, test.cpp, generates seg fault
at run time

How reproducible:
It works fine with Sun CC and IBM xlC. However, I tried
with gcc323, gcc4.1.x and gcc44, they all failed.

Actual results:
$ g++44 -m64 test.cpp
$ ./a.out
in my_object ctor
in my_module ctor, setting up ptr
in my_object ctor
in my_module ctor, setting up ptr
in wire_if ctor
in my_object ctor
in wire_slave_base ctor
in wire_test_target ctor
in top dtor
in wire_test_target dtor
in wire_slave_base dtor
in my_object dtor
before DCASTing to my_module*
Segmentation fault

Expected results:
> ./a.out.sun
in my_object ctor
in my_module ctor, setting up ptr
in my_object ctor
in my_module ctor, setting up ptr
in wire_if ctor
in my_object ctor
in wire_slave_base ctor
in wire_test_target ctor
in top dtor
in wire_test_target dtor
in wire_slave_base dtor
in my_object dtor
before DCASTing to my_module*
after DCASTing to my_module*
in wire_if dtor
in my_module dtor
in my_object dtor
before DCASTing to my_module*
after DCASTing to my_module*
in my_module dtor
in my_object dtor
before DCASTing to my_module*
after DCASTing to my_module*

Additional info:
The same results on all g++ version I have tested. And
failed for both -m32 and -m64.

This looks very similar to a previous Cadence issue:

https://enterprise.redhat.com/issue-tracker/?module=issues&action=view&tid=314103

however, this test program fails using the patch from that issue. I have also reproduced the issue on Fedora 11. I have not tried the latest upstream gcc.

If the reproducer is a well formed C++ program then this looks to be a problem in the dyanmic cast runtime code.
Comment 1 Alan Matsuoka 2010-05-17 17:22:40 EDT
Created attachment 414670 [details]
test.cpp
Comment 2 Jason Merrill 2010-05-18 18:04:46 EDT
As quoted in issue 314103:

12.7/6:   "Dynamic_casts (5.2.7) can be used during construction or
destruction (12.6.2). When a dynamic_cast is used in a constructor
(including from the mem-initializer or brace-or-equal-initializer for a
non-static data member) or in a destructor, or used in a function called
(directly or indirectly) from a constructor or destructor, if the
operand of the dynamic_cast refers to the object under construction or
destruction, this object is considered to be a most derived object that
has the type of the constructor or destructor’s class. If the operand of
the dynamic_cast refers to the object under construction or destruction
and the static type of the operand is not a pointer to or object of the
constructor or destructor’s own class or one of its bases, the
dynamic_cast results in undefined behavior."

Here "my_module_ptr" refers to the my_module base of wire_test_target, and we're destroying the my_object member of the wire_slave_base base of wire_test_target.

In this example wire_if is the primary base class of both wire_test_target and wire_slave_base (see -fdump-class-hierarchy for the details), so once we start destroying wire_slave_base the wire_test_target virtual table pointer now points to a construction vtable for wire_if in wire_slave_base which doesn't know anything about my_module.

But the vtable pointers for my_module and my_object still think they're part of a wire_test_target, so dynamic_cast converts to wire_test_target and then tries to find the offset to the my_module base.  But that offset doesn't exist in the wire_if vtable, so we crash.

I believe this is undefined under the rules above: the pointer refers to the wire_test_target object which is under destruction, but is not a pointer to wire_slave_base or one of its bases.
Comment 3 Jason Merrill 2010-05-18 20:34:54 EDT
But as before, I'm not sure if "the object under destruction" is supposed to mean the complete wire_test_target object or just the my_object subobject.
Comment 4 Jason Merrill 2010-05-18 20:41:41 EDT
Actually, the example in 12.7 paragraph 6 is very similar to this testcase, and I think makes it clear that this testcase has undefined behavior.  I will still investigate further to see if it's possible to do what you want without breaking the ABI.
Comment 5 Jason Merrill 2010-05-19 11:31:33 EDT
I don't think it's possible.  The different from issue 314103 is that in that case the desired my_module was a non-virtual base of C the most derived class, so we didn't need to look in the vtable for the most derived class to find it.

In this case there is a my_module that is a non-virtual base of top, but the my_module that my_module_ptr points to at the time of the dynamic_cast is a virtual base of a wire_test_target object.

Note You need to log in before you can comment on or make changes to this bug.