From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8466 invoked by alias); 2 Dec 2010 16:17:35 -0000 Received: (qmail 8452 invoked by uid 22791); 2 Dec 2010 16:17:33 -0000 X-SWARE-Spam-Status: No, hits=-5.8 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,TW_CP,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from cantor.suse.de (HELO mx1.suse.de) (195.135.220.2) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 02 Dec 2010 16:17:28 +0000 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.221.2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.suse.de (Postfix) with ESMTP id 9943593A00; Thu, 2 Dec 2010 17:17:25 +0100 (CET) Date: Thu, 02 Dec 2010 16:17:00 -0000 From: Richard Guenther To: Martin Jambor Cc: GCC Patches , Jan Hubicka Subject: Re: [PATCH, PR 45934 4/6] Dynamic type change detection In-Reply-To: Message-ID: References: <20101201201618.861802217@virgil.suse.cz> <20101201201711.231211674@virgil.suse.cz> User-Agent: Alpine 2.00 (LNX 1167 2008-08-23) MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2010-12/txt/msg00184.txt.bz2 On Thu, 2 Dec 2010, Richard Guenther wrote: > On Wed, 1 Dec 2010, Martin Jambor wrote: > > > This is the crux of the matter. I'll try to explain what and why I do > > in order to detect sub-object type changes during their construction > > first, below it there is the detection code as it looks like with the > > next patch applied and then there is of course the patch at the end. > > > > I have split the detection code into two patches, this one just > > detects that there is a type change in force and the subsequent one > > also tries to derive the new type. I did this in order to better > > structure the discussion about both and I also intend to commit the > > separately, easing potential bisecting (I hope there will be no reason > > for that of course). If it was absolutely necessary, we could > > postpone the next patch for stage1 but I hope to commit a variant of > > it soon. > > > > Because operations like placement new, memcpy and other byte-per-byte > > operations with objects that have virtual methods are deemed to > > produce code with undefined behavior and there are no unions of > > non-POD types, dynamic type change has a special meaning for > > devirtualization and only refers to what actual virtual method table a > > VMT pointer of an object points to. On the other hand the type in the > > sense of what you get from TREE_TYPE of the base of any given access > > to it is still the same and it is its static type. An important > > property of such objects is that their dynamic types (as given by the > > current VMT) can only be altered in constructors and destructors. > > > > This patch makes special assumptions about both constructors and > > destructors which are all the functions that are allowed to alter the > > dynamic types. It assumes that destructors begin with assignment into > > all VMT pointers and that constructors essentially look in the > > following way: > > > > 1) The very first thing they do is that they call constructors of the > > components (including ancestor sub-objects) that have them. > > > > 2) Then VMT pointers of this and all its ancestors is set to new > > values corresponding to the type corresponding to the constructor. > > > > 3) Only afterwards, other stuff such as the code written by the user > > is run. Only this may include calling virtual functions, directly > > or indirectly. > > > > There is no way to call a constructor of an ancestor sub-object in any > > other way (or any component for that matter but type is interesting > > only for ancestors). > > > > This means that we do not have to care whether constructors get the > > correct type information because they will always change it (in fact, > > if we define the type to be given by the VMT pointer, it is > > undefined). You can still reach wrong conclusions for the dynamic type of *p in the following testcase: extern "C" void abort (void); extern "C" void *malloc(__SIZE_TYPE__); inline void* operator new(__SIZE_TYPE__, void* __p) throw() { return __p; } int x; class A { public: virtual ~A() { } }; class B : public A { public: virtual ~B() { if (x == 1) abort (); x = 1; } }; void __attribute__((noinline,noclone)) foo (void *p) { B *b = reinterpret_cast(p); b->~B(); new (p) A; } int main() { void *p = __builtin_malloc (sizeof (B)); new (p) B; foo(p); reinterpret_cast(p)->~A(); return 0; } if you ignore the call to foo() then you see a vtable pointer store to make *p a B, but in reality at the time of the virtual call to the destructor it is an A. Similar, if you add a char data[256]; member to A then a { B x; new (&x.data) A; reinterpret_cast(&x.data)->~A; } might possibly mis-lead you as to the type of B at destruction time (this example is more similar to the array issue I raised). Richard.