1

Is it safe to call delete on a base-class pointer to a heap object allocated by a dynamically loaded library? Both that lib and the client were built by the same compiler (GCC).

Keith Russell
  • 560
  • 4
  • 12
  • (The loaded lib allocates it by calling "new" in the usual way - not using in-place "new" upon a memory address I provide to it, or anything like that.) – Keith Russell Feb 22 '17 at 17:00
  • 1
    Looks like this question comes from usage of MS stuff. No, Linux/Unix system implemented shared libs properly the first place, not that crap from MS – Slava Feb 22 '17 at 17:20
  • If I could find an official-ish reference saying as much, that'd solve my problem. :) – Keith Russell Feb 22 '17 at 17:25
  • 1
    @KeithRussell there is no universal official reference about shared libraries in C++, because the standard does not specify shared libraries. To find official documentation you must limit your search to particular implementation of shared libraries. – eerorika Feb 22 '17 at 17:28
  • @KeithRussell this is normal way which should work by default, MS as usually ignored standard and made their own way. So I doubt you would find official reference that Linux does it properly. – Slava Feb 22 '17 at 17:36

3 Answers3

4

It is safe to delete the pointer if and only if

  • The destructor of the base class is virtual.
  • The pointer was returned by new (not new[], not malloc, not mmap, ...)
  • You are the sole owner of the pointer. In other words: If no other piece of code (within or out of the dll) is going to use or destroy the pointed object.

As far as the standard is concerned, the library must have linked with the same version of runtime library that define the allocation functions. Same requirement applies to separate object files that are linked together statically.

Technically multiple different implementation of memory allocation functions violates the one definition rule, but a C++ implementation that extends the language with standard libraries may possibly extend the language to allow multiple different implementations for those functions. If that is the case for the implementation that you use, then it might not be safe to deallocate memory allocated by the shared library unless you can prove that same versions were used for both the library and the code that deletes the object.


Whether it is safe or not, it is a bad idea to provide an API that returns resources (such as dynamic memory), but not API that takes care of releasing those resources.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • 1
    Wrong, the destructor doesn't have to be virtual for the delete to be safe. It only has be virtual if you want any derived class destructors to be called. – Emil Laine Feb 22 '17 at 16:59
  • 1
    @tuple_cat *"if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and **the static type shall have a virtual destructor or the behavior is undefined**."* So sayeth the standard. – eerorika Feb 22 '17 at 17:01
  • @tuple wrong - the standard says that deleting a derived object via a base pointer is undefined behaviour if the base destructor is not virtual. The standard doesn't say what destructors may or may not be called in this circumstance. –  Feb 22 '17 at 17:02
  • @user2079303 Thanks, learned something. Never heard that before. – Emil Laine Feb 22 '17 at 17:05
  • Unfortunately this is from standard C++ point of view, but MS thinks differently: http://stackoverflow.com/questions/443147/c-mix-new-delete-between-libs – Slava Feb 22 '17 at 17:23
  • @Slava I expanded the answer a bit to consider language extensions in general. – eerorika Feb 22 '17 at 17:40
1

It depends on the version of the compiler and flags that dynamic library was compiled with.

The library's call to new grabs the object from the heap controlled by the library.

Your call to delete places the object back to the heap controlled by your executable.

This may or may not be the same heap managed by the same library.

The safe way is to wrap the delete in the library call, like fopen/fclose.

  • Hearing a rumor about this is what prompted my question, actually. I'm interested to know whether this two-heaps behavior is only done by obscure OSes, or whether e.g. mainstream Linux distros do it. – Keith Russell Feb 22 '17 at 17:15
  • I saw it when dynamic library was compiled wit an older version of g++. It was all long ago, may be there is a better solution by now. In any case, think of executable compiled with g++ and library compiled with an Intel compiler :) –  Feb 22 '17 at 17:21
  • There in no such thing as "heap controlled by the library" in Unix/Linux world. As OP question says gcc, which probably means Linux, this is not a problem. – Slava Feb 22 '17 at 17:28
  • @Slava At the very least, if the dynamic library was compiled with static C runtime, you'll have that situation. And even if the library links to C runtime dynamically, if the C runtime version of library is very old, it will not be able to share the executable's version. So you will have two different heap data structures. –  Feb 22 '17 at 18:40
  • @Arkadiy what OS do you mean? If Linux this does not make any sense. – Slava Feb 22 '17 at 19:02
0

Yes, if it was allocated with new, and if the library (or any other code) doesn't try to use the object after the delete.

Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • 1
    The destructors have to be declared `virtual`. – mch Feb 22 '17 at 16:57
  • @mch Can you elaborate why? – Emil Laine Feb 22 '17 at 16:58
  • If the destructor of the base class is not virtual, it will not call the destructor of the derived class when you delete the base pointer. – mch Feb 22 '17 at 16:59
  • Yes, but having a non-virtual dtor doesn't make delete any less safe. It might leak memory if you should be invoking the derived dtor, but that's it. – Emil Laine Feb 22 '17 at 17:03
  • 1
    @tuple_cat standard doesn't guarantee that. A conforming compiler is free to launch nethack, for example. Or just crash. Or corrupt your data. – eerorika Feb 22 '17 at 17:04