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

ATTIA, Emmanuel emmanuel.attia at philips.com
Sat Oct 5 07:48:49 PDT 2013


>/ 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:

But the lifetime of the object has not ended.
It would only end when either a non-trivial destructor is called either when the memory is released.

This doesn't mean by chance there is no destructor so nothing bad happens, it mean if there is no destructor so, according to the standard, the compiler should consider the object alive until the memory is released.

I'm sorry but the statement  is clear enough:
> "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."

De : Matthieu Monrocq [mailto:matthieu.monrocq at gmail.com]
Envoyé : samedi 5 octobre 2013 14:22
À : Richard Smith
Cc : ATTIA, Emmanuel; cfe-dev at cs.uiuc.edu Developers
Objet : Re: [cfe-dev] is delete on abstract with non-virtal ever safe?



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

On 4 Oct 2013 02:49, "emmanuel.attia" <emmanuel.attia at philips.com<mailto: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<mailto: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<mailto: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

________________________________
The information contained in this message may be confidential and legally protected under applicable law. The message is intended solely for the addressee(s). If you are not the intended recipient, you are hereby notified that any use, forwarding, dissemination, or reproduction of this message is strictly prohibited and may be unlawful. If you are not the intended recipient, please contact the sender by return e-mail and destroy all copies of the original message.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20131005/0a216f58/attachment.html>


More information about the cfe-dev mailing list