Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

Delete called in virtual destructor #34490

Closed Quuxplusone closed 6 years ago

Quuxplusone commented 6 years ago
Bugzilla Link PR35517
Status RESOLVED INVALID
Importance P enhancement
Reported by Konstantin Morshnev (moko@design.ru)
Reported on 2017-12-04 06:27:54 -0800
Last modified on 2017-12-06 09:33:53 -0800
Version unspecified
Hardware PC All
CC dblaikie@gmail.com, dgregor@apple.com, efriedma@quicinc.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
The following code produces link error with all available to us clang versions.
It compiles when destructor is not virtual. Note that there is no "new"
operator calls, only "delete" is called. The code also compiles with gcc
starting with version 6.1.

--------------------------------------

/tmp/example-d524df.o: In function `operator delete(void*)':
23 : <source>:23: undefined reference to `no_such_methood()'
clang-5.0: error: linker command failed with exit code 1 (use -v to see
invocation)

--------------------------------------
URL to play with the code: https://godbolt.org/g/1ifDyg

--------------------------------------
#include <new>
#include <cstdlib>

#pragma clang diagnostic ignored "-Winline-new-delete"

 void no_such_methood();
 //void no_such_methood(){asm ("nop");};

inline void* operator new(size_t size) throw(std::bad_alloc)
{
  no_such_methood();
  return malloc(size);
}

inline void* operator new[](size_t size) throw(std::bad_alloc)
{
  no_such_methood();
  return malloc(size);
}

inline void operator delete(void* ptr) throw()
{
  no_such_methood();
  free(ptr);
}

inline void operator delete[](void* ptr) throw()
{
  no_such_methood();
  free(ptr);
}

struct MyStructBase
{
     virtual ~MyStructBase()
     {
  }
};

struct MyStruct : MyStructBase
{
};

int main(void)
{
  MyStruct ss;
  return 0;
}

--------------------------------------

That is why we use the such code in our project:
https://stackoverflow.com/questions/18365804/is-it-possible-to-completely-disable-the-default-c-new-operator

--------------------------------------
Possibly it compiles in gcc after this change:

http://patchwork.ozlabs.org/patch/604210/

--------------------------------------
Quuxplusone commented 6 years ago

This is how the ABI works. https://eli.thegreenplace.net/2015/c-deleting-destructors-and-virtual-operator-delete/ has a good description of deleting destructors.

Also, please use the cfe-dev mailing list, not the bugtracker, for questions about clang's behavior.

Quuxplusone commented 6 years ago
(In reply to Konstantin Morshnev from comment #0)
> Possibly it compiles in gcc after this change:
>
> http://patchwork.ozlabs.org/patch/604210/

FWIW, your testcase only compiles in GCC 6.1 because they changed their default
standard mode to C++14, and that causes your code to call "operator
delete(void*, size_t)" instead of "operator delete(void*)".
Quuxplusone commented 6 years ago
> has a good description of deleting destructors.

The description is clear and we know it. But it is about dynamic objects
(MyStruct *ss=new MyStruct), and we have a stack object (MyStruct ss).

And if you'll and some printfs (like https://godbolt.org/g/fW4QZk) you'll see,
that delete is not called. It looks like there are two destructor versions are
generated - one with delete call and one without. But if the one with delete is
not referenced, why it is not optimized out?

> FWIW, your testcase only compiles in GCC 6.1 because they changed their
default standard mode to C++14

Thx for this note.

P.S. As a workaround we are temporary disabling virtual destructors to check
that build-in delete is not used in our code, but it's not very convenient.
Quuxplusone commented 6 years ago

The deleting destructor is not optimized out because it's referenced by the vtable.