1

My question are probably related to here and here: Q If we create a type instance of class defined in another DLL on stack, is it safe?

// A DLL
class DLL_EXPORT Foo;


// Target exe
int main()
{
     // bad, not supposed to do this:
     Foo* x = get_instance_from_dll();
     delete x;

     // **Question**:
     // what about stack variable of type declared in the DLL?
     // is this alright?
     Foo x;

}
Community
  • 1
  • 1
Wilson
  • 141
  • 1
  • 8
  • A DLL can export member functions of a class, but the definition of the class is compiled into your executable via the header file. – Jonathan Potter Jul 11 '14 at 08:01
  • What makes you say it's bad to get a pointer to an instance in an DLL on the stack? The rule I know is "if you call new from the DLL you must call delete from the same DLL" –  Jul 11 '14 at 08:03
  • @JonathanPotter Should the DLL and EXE are built using different compilers, both of them may produce a different memory layout for class Foo? Does this imply that the Foo allocated on stack and Foo new-ed in the DLL are different? – Wilson Jul 11 '14 at 08:39
  • @snowandotherjoys So it's perfectly fine to declare Foo on stack in the exe? "Foo* x = new Foo();" is safe too? – Wilson Jul 11 '14 at 08:40
  • How are the dll and exe built? Do they use the same compiler with the same flags, or are the different compilers (or even versions of the compiler)? – Niall Jul 11 '14 at 10:25
  • @Niall They are from different compilers. – Wilson Jul 12 '14 at 23:25
  • @Wilson, Hans' answer is correct for your situation. As an alternative, you could use a pure C API and offer a header only C++ wrapper, but that may be more effort than its worth. – Niall Jul 13 '14 at 06:16

2 Answers2

1

No, it is not safe. There are three basic problems with using a DLL that exposes C++ code:

  • The DLL using different allocator. So your delete can't destroy the object. You already know about that one.

  • Your compiler not calculating the same layout for the class object. Particularly a problem if it has any members that are standard C++ library classes, like std::string or std::vector. That DLL could have been compiled with a different version of those classes. Like one that preceded C++11, it caused lots of changes in the std class implementations. Or used optimized release build settings and does not have iterator debugging enabled and you do.

  • Any exception objects that the DLL might throw across the module boundary suffer from the above two problems. This one is easy to overlook when you fix your DLL interface to be safe, you can't easily do the same thing for exceptions.

The second bullet is your nemesis, your compiler will compute the wrong size for the object and will not reserve the correct amount of space for it on the stack frame. Particularly nasty when the actual object size is larger, the code in the DLL will overwrite other variables on your stack. Pretty hard to diagnose.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • If I use pure abstract interface (pImpl) or shared_ptr (std/Boost) to expose my DLL classes, would they be still susceptible to Second Bullet and Third one? (also consider cases where compiler versions are different) – Wilson Jul 12 '14 at 23:29
  • Abstract interfaces are good, just a jump-table of addresses. Underpinning of COM, implementation inheritance is *much* harder to keep compatible. Error handling is the typical nemesis, the reason I added the 3rd bullet. – Hans Passant Jul 12 '14 at 23:48
0

As I understand it the only restrictions here (because of the memory manages) is that new and delete must be called by the same module (basically if you new it in a DLL delete it in the same DLL).

If you are creating the object on the stack this is simply not a problem.

EDIT: You asked about the case with the new in the constructor: The constructor and destructor will be run in the DLL's space, so as long as the new AND the delete are in the DLL (presumably in the constructor and destructor) that isn't a problem.

Also think you should take the Hans' advice very seriously - if the header files used in the two compilations are different for some reason (different versions) or the modules were compiled with different compilers or the compiler settings were different in some ways then you can easily have difficult to diagnose bugs.

If you are not building both of the modules together with the same tools and releasing then together you shouldn;t experience ay problems.

Elemental
  • 7,365
  • 2
  • 28
  • 33
  • *If you are creating the object on the stack this is simply not a problem.* Even if there a "new" operation in the constructor? – Wilson Jul 11 '14 at 08:36