[cfe-dev] is delete on abstract with non-virtal ever safe?

Matthieu Monrocq matthieu.monrocq at gmail.com
Sat Oct 5 05:22:09 PDT 2013


On Fri, Oct 4, 2013 at 7:15 PM, Richard Smith <richard at metafoo.co.uk> wrote:

>
> On 4 Oct 2013 02:49, "emmanuel.attia" <emmanuel.attia at philips.com> wrote:
> >
> > > This has undefined behavior. You're calling a virtual function on an
> object
> > whose lifetime has ended (the destructor has already been called).
> >
> > my_destroy_interface has no destructor so the vtable is not cleared until
> > the memory is released (since nothing alters it before i get in the
> operator
> > delete overload).
> >
> > Referring to the standards (i'm not sure its the right pdf):
> > "The lifetime of an object of type T ends when:
> > — if T is a class type with a non-trivial destructor (12.4), the
> destructor
> > call starts, or
> > — the storage which the object occupies is reused or released."
> > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf
> >
> > And that make totally sense since if i add a  (non-virtual) destructor it
> > still flies, unless the destructor is non trivial (in that case i get as
> > expected a pure virtual function call).
>
> This is sort of beside the point, since you had undefined behaviour
> earlier:
>
> > > This has undefined behavior (you're using 'delete', the static and
> dynamic
> > > types don't match, and your base class does not have a virtual
> > > destructor).
> >
> > That's the point, i call the overload "my_destroy_interface::operator
> > delete" and not the global delete operator. Since my_destroy_interface
> has
> > no (non trivial) destructor this is the only thing happening when calling
> > delete on a pointer to my_destroy_interface.
>
> You can't reason like that about undefined behaviour. You deleted an
> object thorough the wrong static type and the dtor is not virtual, so
> you've already lost.
>
> > > Nope. See above. Or try giving my_destroy_interface a user-declared
> > > (non-virtual) destructor, and watch as it either gets called twice or
> your
> > > program starts to die due to a pure virtual function call (depending on
> > > implementation details).
> >
> > Giving to my_destructor_interface a virtual destructor would make it
> called
> > twice as you said, thats why it's not there in this construct (and it
> makes
> > sense since its an interface).
> >
> >
> >
> >
> > --
> > View this message in context:
> http://clang-developers.42468.n3.nabble.com/is-delete-on-abstract-with-non-virtal-ever-safe-tp4025653p4034880.html
> > Sent from the Clang Developers mailing list archive at Nabble.com.
> >
> > _______________________________________________
> > cfe-dev mailing list
> > cfe-dev at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>
>
I think I found a quote in the n3485 C++ Working Draft that explains a tad
more, in 3.8 [basic.life]:

5/ Before the lifetime of an object has started but after the storage which
the object will occupy has been
allocated or, after the lifetime of an object has ended and before the
storage which the object occupied is
reused or released, any pointer that refers to the storage location where
the object will be or was located
may be used but only in limited ways. [...] The program has undefined
behavior if:

[...]

— the pointer is used to access a non-static data member or call a
non-static member function of the
object, or

[...]

— the pointer is used as the operand of a static_cast (5.2.9), except when
the conversion is to pointer
to cv void, or to pointer to cv void and subsequently to pointer to either
cv char or cv unsigned
char, or

[...]


So unfortunately the scheme you are proposing is violating the Standard at
least twice, because as far as the Standard goes your object is already
dead (whether its destructor had any effect or not does not matter).
Specifically, I could see one of `-fsanitize=undefined` or
`-fsanitize=memory` (for example) overwriting the memory with 0xdeadbeef
between the call to the destructor and the call to your specific operator
delete.

I am sorry I had not remembered this point in our prior discussion; I had
forgotten that operator new and operator delete are only supposed to deal
with raw memory and not objects.

-- Matthieu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20131005/4a0b954e/attachment.html>


More information about the cfe-dev mailing list