From mboxrd@z Thu Jan 1 00:00:00 1970 From: pacman@world.std.com To: gcc-gnats@gcc.gnu.org Subject: c++/2811: mult.inheritance+overload+contravariance=SEGV Date: Sun, 13 May 2001 01:06:00 -0000 Message-id: <20010513080556.30622.qmail@sourceware.cygnus.com> X-SW-Source: 2001-05/msg00324.html List-Id: >Number: 2811 >Category: c++ >Synopsis: mult.inheritance+overload+contravariance=SEGV >Confidential: no >Severity: serious >Priority: medium >Responsible: unassigned >State: open >Class: wrong-code >Submitter-Id: net >Arrival-Date: Sun May 13 01:06:01 PDT 2001 >Closed-Date: >Last-Modified: >Originator: Alan Curry >Release: gcc version 2.95.2 20000220 (Debian GNU/Linux) >Organization: >Environment: Debian 2.2, i686 >Description: When assigning to a pointer-to-member-function, if the class of the lvalue is a subclass of the class of the rvalue (taking advantage of the contravariance of function pointers), and it is not the _first_ subclass (meaning the rvalue must be multiply-inherited), the compiler must record within the pointer's value an offset which is to be added to a pointer to the subclass to convert it into a pointer to the superclass, suitable for use by the function being called. When an expression of the form &Foo::bar is assigned to a pointer-to-member-function, and Foo::bar is overloaded, the compiler must choose one of the Foo::bar candidates based on the argument types of the lvalue. It is possible for both of these conditions to exist in the same assignment, and in such a case g++ 2.95.x incorrectly records the subclass-to-superclass offset as 0, resulting in a bad "this" pointer being passed when a call is made through the function pointer. I'm supplying a sample program which demonstrates this problem with the contravariant assignment of a pointer to an overloaded member function of a multiply inherited class. It compiles clean under -Wall, and segfaults reliably, since I have managed to put a null pointer in the location g++ is incorrectly dereferencing. I ran this through CodeSourcery's Online Test Compilation and it seems the 3.0 snapshot there does not have the bug. It also seems that 3.0 uses a completely different format for pointers to member functions, so it's not surprising that it doesn't have the bug. Is it just me or does "contravariant assignment of a pointer to an overloaded member function of a multiply inherited class" sound like a really good title for a movie? >How-To-Repeat: int ten=10; int otherten=10; class Super { public: int *dat; Super::Super(int *arg) { this->dat=arg; } int x(int *i) { return *i - *this->dat; } int x(void) { return 0; } }; class Monkey { public: int *wrench; Monkey::Monkey() { wrench=(int *)0; } }; class Sub : public Monkey, public Super { public: Sub::Sub() : Super(&ten) {} }; int (Sub::*p)(int *); int (Super::*fp)(int *); int main(void) { Sub v; #if 0 fp=&Super::x; // resolve overloaded name - works fine p=fp; // resolve contravariance - works fine #else p=&Super::x; // attempt to resolve overloaded name and contravariance in // the same assignment - breaks #endif return (v.*p)(&otherten); } >Fix: You can avoid this bug by using a temporary variable and two separate assignments, as shown in the #if 0'ed section of my sample code. But first you'd have to know about this bug, which seems unlikely. >Release-Note: >Audit-Trail: >Unformatted: