Given: Executable uses dll. They have different c/c++ runtime. Which restrictions do exist in interface between them?
Besides they use the same compiler, the same Boost version (but different precompiled boost libs).
I understand that different runtime can have different heaps. So, delete must correspond to new from the same heap.
Most important that we cant pass via interface STL objects because when we build exe STL object are linked with one runtime
and when building dll the same object(if we pass it by reference or copy via interface) will be linked with another runtime.
And another runtime can have different implementation of that object.
Let’s consider cases:
-
I think the following is safe. Dll exports function which has parameter: reference to exported user defined class that contains private STL class as member.
Dll allocates memory for this object. Exe calls Release method of this object when want to delete it. -
I think the following is NOT safe. User defined class is instantiated in exe and passed via exe/dll interface.
This class contains private STL class as member. exe and dll share headers/implementation files of this user class.
When this class is built in separate projects different STL implementations will be used. For example different implementation
of string::size() (from different runtimes) will be applied for the same object in memory. -
I think the following is safe. User defined class is instantiated in exe and passed via exe/dll interface.
This class doesn’t depend on Standard library, it uses only primitive C++ types. exe and dll share headers/implementation files of this user class.
Also we must control that new and delete correspond to the same heap. For example we can overload new / delete so them use ::GetProcessHeap. -
I think the following is NOT safe: passing boost objects via exe/dll interface because they can depend on Standard library classes. Also delete may not correspond to new’s heap.
-
I think the following is NOT safe: even if we pass boost objects via exe/dll interface and they don’t depend on Standard library classes but not implemented as header only – than the object can be created with one boost lib (for one runtime)and used with another boost lib(for another runtime). Also delete may not correspond to new’s heap.
Also I want to use some flavor of smart pointer to pass reference to objects (mentioned in item 3) from exe to dll and from dll to exe.
I think this smart pointer should also overload new/delete to allocate reference counter from default process heap.
When it will try to delete pointed object it will call delete that overloaded by this object (as in item3)
For objects from item 1 I want to use custom smart pointer which will call release method of pointed object
(as boost::shared_ptr with custom release)
Which problems were not mentioned? Correct me please.
The general answer to your question is: doing something to an object received from an EXE/DLL is safe if what is actually done does not depend on the runtime. E.g. vtable calls, function pointer calls, explicit function calls from DLL.
Things that depend on the runtime (inline methods from header files, anything making any assumptions about STL object layout, etc.) are unsafe.
Coming back to your examples:
If you call the Release() method you should be careful and ensure that you’ll call the implementation of Release() from the DLL and not another implementation that was created by compiler making the EXE file. The easiest way to ensure it is to make Release() virtual so that the call is always a call using a method pointer from vtable (provided by DLL).
Right, inline methods from STL like string::size() will cause problems here.
Remarks:
There are a few low-probability things that may cause problems not mentioned above:
Having things summarized, it is recommended to look how things are implemented in Microsoft COM and design something similar. I.e. restrict the EXE/DLL interaction to:
Simple clearly defined structures. Ensure that the alignment options for all compilers match. If you want to use non-trivial structures and you are using different compilers, better be paranoid and put checks like these:
C-like functions passing and/or returning pointers to interfaces.