A colleague and I were having an interesting discussion about memory allocation when working with shared libraries and "where" code is actually executed.
Hint: I'm explicitly looking for answers in general terms. I know that the following points would work when using the exact same compiler and settings when building the shared library and application. I want to assume that the DLL is built using a completely different compiler than the application.
Given the following struct Foo:
struct Foo
{
int m_FooBar = 1;
const char* GetBar()
{
return m_Bar.c_str();
}
void SetBar(const char* value)
{
m_Bar = value;
}
private:
std::string m_Bar;
};
Assuming the shared library exposes a function Foo* GetFoo() and an external application calls it:
1.) What happens if the external application calls foo->SetBar("Hello")?
Would SetBar be executed inside the DLL and thus the memory allocation of m_Bar be safe or would the memory allocation happen inside the external application and thus lead to issues?
2.) What happens if the external application copies the instance pointed to by the returned pointer?
Judging by the many posts out there warning against passing std::string over DLL boundaries I assume that caused by potential different ABIs a default copy could cause problems. Is that correct?
3.) Would it be safe to define custom copy constructors and assignment operators that construct m_Bar by calling .c_str() on the passed instance so that those methods only rely on the API of std::string and not on the ABI?
Hope some C++ gurus can answer some of these questions and shed some light on this topic.
1.) What happens if the external application calls foo->SetBar("Hello")?
Would SetBar be executed inside the DLL and thus the memory allocation of m_Bar be safe or would the memory allocation happen inside the external application and thus lead to issues?
There are many problems, not just concerning memory allocations or mixing up C runtime libraries.
For starters, Foo may not even be the same size, std::string definition may be a completely different one, etc. etc. etc.
2.) What happens if the external application copies the instance pointed to by the returned pointer?
Judging by the many posts out there warning against passing std::string over DLL boundaries I assume that caused by potential different ABIs a default copy could cause problems. Is that correct?
No need to copy to get into trouble: since you don't know anything about the memory it points to, even using the Foo you were given will break everything.
3.) Would it be safe to define custom copy constructors and assignment operators that construct m_Bar by calling .c_str() on the passed instance so that those methods only rely on the API of std::string and not on the ABI?
Your general idea of trying to go to the lowest level is good. However, trying to play with m_Bar isn't.
Instead, provide a plain C interface and optionally provide wrapper classes in a header. And even then, be careful about allocating/deallocating/using system resources if you are linking with different C runtime libraries (in Windows).
Related
So, I have a C++ library with a statically linked copy of the MSVCRT. I want for anyone to be able to use my library with any version of the MSVC Runtime. What is the best way to accomplish this goal?
I'm already being quite careful with how things are done.
Memory never passes the DLL barrier to be freed
Runtime C++ objects aren't passed across barriers (ie, vectors, maps, etc.. unless they were created on that side of the barrier)
No file handles or resource handles are passed between barriers
Yet, I still have some simple code that causes heap corruption.
I have an object like so in my library:
class Foos
{
public: //There is an Add method, but it's not used, so not relevant here
DLL_API Foos();
DLL_API ~Foos();
private:
std::map<std::wstring, Foo*> map;
};
Foos::~Foos()
{
// start at the begining and go to the end deleting the data object
for(std::map<std::wstring, Foo*>::iterator it = map.begin(); it != map.end(); it++)
{
delete it->second;
}
map.clear();
}
And then I use it from my application like so:
void bar() {
Foos list;
}
After I call this function from anywhere, I get a debug warning about stack corruption. And If I actually let it run out, it actually does corrupt the stack and segfault.
My calling application is compiled with Visual Studio 2012 platform tools. The library is compiled using Visual Studio 2010 platform tools.
Is this just something I should absolutely not be doing, or am I actually violating the rules for using multiple runtimes?
Memory never passes the DLL barrier
But, it does. Many times in fact. Your application created the storage for the class object, in this case on the stack. And then passes a pointer to the methods in the library. Starting with the constructor call. That pointer is this inside the library code.
What goes wrong in a scenario like this one is that it didn't create the correct amount of storage. You got the VS2012 compiler to look at your class declaration. It uses the VS2012 implementation of std::map. Your library however was compiled with VS2010, it uses a completely different implementation of std::map. With an entirely different size. Huge changes thanks to C++11.
This is just complete memory corruption at work, code in your application that writes stack variables will corrupt the std::map. And the other way around.
Exposing C++ classes across module boundaries are filled with traps like that. Only ever consider it when you can guarantee that everything is compiled with the exact same compiler version and the exact same settings. No shortcuts on that, you can't mix Debug and Release build code either. Crafting the library so no implementation details are exposed is certainly possible, you have to abide by these rules:
Only expose pure interfaces with virtual methods, argument types must be simple types or interface pointers.
Use a class factory to create the interface instance
Use reference counting for memory management so it is always the library that releases.
Nail down core details like packing and calling convention with hard rules.
Never allow exceptions to cross the module boundary, only use error codes.
You'd be well on you way to write COM code by then, also the style you see used in for example DirectX.
map member variable is still created by application with some internal data allocated by application and not DLL (and they may use different implementations of map). As a rule of thumb don't use stack objects from DLLs, add something like Foos * CreateFoos() in your DLL.
Runtime C++ objects aren't passed across barriers (ie, vectors, maps,
etc.. unless they were created on that side of the barrier)
You are doing exactly that. Your Foos object is being created by the main program on the stack and then being used in the library. The object contains a map as a part of it...
When you compile the main program it looks at the header files etc to determine how much stack space to allocate for the Foos object. And the calls the constructor which is defined in the library... Which might have been expecting an entirely different layout/size of the object
It may not fit your needs, but don't forgot that implementing the whole thing in header files simplifies the problem (sort of) :-)
I have a test app that is linked with some DLLs (or .so's). In my main app I defined a global new/delete like this:
void* operator new(size_t n)
{
....
}
void operator delete(void* p)
{
...
}
But I noticed the operators are only called for things I allocate in my main app, but not if one of the DLLs does.
How do I make allocations in the DLLs go through my operator new/delete? (This should also include memory allocated by STL, so if one of the DLLs has an std::string, I'd like my operator new to be called when STL allocates its std::string internal buffer).
I'm more interested in a Windows solution, but a Linux one would also be appreciated.
edit: perhaps I wasn't clear originally, this test app I was doing was meant to track memory usage for a few auto-generated classes defined in a DLL. Creating my own allocator and using that in the generated code STL structures isn't an option, more so there are other non-STL allocations. But seeing the answers, I think the best option is either to use a profiler or simply monitor the memory usage using perfmon.
I'd like my operator new to be called when STL allocates its std::string internal buffer
typedef std::basic_string<char, std::char_traits<char>, ALLOCATOR> mystring;
The code in the DLLs already uses its own new implementation, and there's no good reason why defining your own implementation should magically change the implementation that the DLLs use (what if they use their own custom implementation?).
So if you want the strings to use your allocator, you need to explicitly create them as such.
Anything that is intended to use your global definitions must be compiled with those definitions available. The technique you use will not override anything already compiled in DLLs or even other source files that don't include these definitions. In many cases the allocators and standard functions will also not use these functions even when visible.
If you really need to do this you'll have to intercept calls to malloc (and other allocation routine). This isn't easy. You can't simply do it from the code. You'll have to tell the linker how to do this. On Linux I think this is LD_PRELOAD, though I can't remember, and on Windows I'm not sure at all.
If you can indicate why you'd like to do this perhaps I can offer an alternate solution.
There is no way to completely do what you want to do. There are too many corner cases where memory is leaked.
The closest I think you can get is by doing the following:
Each class in your dll/.so will have to have a static factory/destroy method. Pass a pointer to an allocation function to the factory and the deallocation function to the destroy method in each class in each dll/.so.
For an example of how to get close, google for the HORDE memory allocation library, which does get close.
Another thing to look at is the various C++ class plugin libraries that allow you to load any dll/.so as a plugin. Last time I checked there were at least 10 such libraries with source in the googlesphere. :)
I'm having some trouble with a dynamically linked library calling my overloaded operator delete but not my operator new. My exe looks something like this:
class A {
public:
void func() {
t = dynLib::Type::CreateObject();
}
dynLib::Type t;
};
void main() {
A a;
a.func();
}
And then I have a statically linked library where I have my global overloaded operators
and the dynamically linked library that's causing the problem. Basically what happens is, the dynLib::Type type contains an std::vector to which it adds an element in its constructor. So the type looks something like this
class Type {
public:
Type() {
v.push_back( T() );
}
std::vector< T > v;
};
When func() is called, a new instance of Type is created, passed by value and then assigned to t. The operator= in work there copies over the std::vector also through its operator=. This in turn calls deallocate on the old std::vector in t, since it already had an element added in its constructor. This deallocate call ends up calling my operator delete. The problem is, my operator new was never called so it's deleting a pointer in a completely different memory space (memory logging shows this).
Now, I'm probably just missing something. Since class A above holds a dynLib::Type object, it might get constructed before my operator new (from the static library) gets linked. Is that even possible? I'm not quite sure at which point the constructor of the composed dynLib::Type is called. The dynamic library uses the default stl allocators so it doesn't do anything funky.
I've tried recreating the same situation without the dynamically linked library, just by having the Type class in my exe. This doesn't cause the issue though so it leads me to believe it must have something to do with the link order.
This is badness. You are in effect using STL objects across the DLL boundary. This is a big no-no and will continue causing headaches for you. The most likely source of linking problems is how the executable and the DLL use CRT. If one uses static (/MT) and the other is dynamic (/MD) you will see all sorts of weirdness, and overloaded operator new is usually the first one to glitch.
If the CRT is consistent across the board, then it should work, but it's still not recommended to use the DLL as though it's a static library.
Try to refactor the code so that you don't have to construct Type outside of the DLL, see if that makes it better.
I have a function foo() in dll A.dll, whose definition is as follows
vector<CustomObject> foo()
{
vector<CustomObject> customObjectCollection;
//code which populates customObjectCollection goes here
return customObjectCollection;
}
I am referring this method vector foo() of dll A from exe B
When i make a call to the function foo from B, I get an unhandled exception which says
"unhandled exception at
0x10487b3f(msvcp90d.dll) in B.exe"
0xC0000005: Access violation while
writing to the location 0xfdfdfdfd".
Note:type CustomObject does not implement copy constructor
When i tried to debug by attaching B.exe to A.dll, I found that inside method vector foo(), the vector gets populated without any problem but when the control returns to B.exe the valves in vector doesnot get copied !!!
Also, if method foo returns vector by reference , exception doesnot occur and B.exe receives an empty vetor.
what is the issue ?? Is it happening as I have not implemented copy constructor for CustomObject.
Any help is greatly appreciated
(Apologies for not articulating the question properly)
Thanks
jeel
This is a classic symptom of mismatched runtime libraries. You have to make sure that both the EXE and the DLL are linked to the dynamic C++ library (DLL version).
If one (or both) are linked with the static C++ runtime (LIB version), you'll get memory violations since there will be two instances of the runtime library with different address spaces.
First of all you should not return references to local objects declared on stack.
Second: there are requirements for elements to be able to be used in STL containers
1) Copy constructor
2) Assignment operator
3) Public destructor
There are more container specific (like sorting criterium for associative containers).
Copy constructor will be created as well as assignment operator (thanks to the compiler) so unless you explicitly hide them - your object has them (if you did not have copy constructor, compiler would complain).
But these implicit copy constructor and assignment operator may not be smart enough, so you may want to implement your own. For instance: lets say that you CustomObject in constructor creates an instance of some class with new and keep it as pointer to be destroyed in the destructor. Default copy constructor will make a shallow copy, so this will result in two objects holding the same pointer. Once one of them is destroyed, second one becomes inconsistent (it holds pointer that has already been released).
Final note: try not to return vector by value. A lot of copying is involved. Declare it in the caller on stack and pass it as reference to you foo.
Probably the safest way would be:
bool foo(vector<someclass*> &customObjectCollection)
{
//code which populates customObjectCollection goes here
return success
}
This way the calling program creates and maintains the vector so there's no need for copying. Caller would do
vector<someclass *> customObjectCollection;
foo(customObjectCollection);
Also, depending on what you are doing exactly, note the use of a vector of someclass pointers rather than someclass objects.
There are a number of possibilities here, and you haven't told us enough to determine which is most likely to apply.
One possibility is (semi-)unique to putting the code in a DLL. If you link the standard library statically, each module (EXE, DLL) gets its own memory management, including its own heap, so quite a few operations that try to transfer ownership of memory between one module and another will fail for (seemingly) strange reasons. The cure for this type of problem is usually to link to the standard library in a DLL for all your modules. This gives one copy of the standard library shared throughout the application, so passing ownership between modules doesn't cause a problem.
Another possibility is that your CustomObject class isn't handling copying appropriately. Since you've told us nothing about its internals, it's impossible for us to guess what you might need to do here.
I have an abstract class in my dll.
class IBase {
protected:
virtual ~IBase() = 0;
public:
virtual void f() = 0;
};
I want to get IBase in my exe-file which loads dll.
First way is to create following function
IBase * CreateInterface();
and to add the virtual function Release() in IBase.
Second way is to create another function
boost::shared_ptr<IBase> CreateInterface();
and no Release() function is needed.
Questions.
1) Is it true that the destructor and memory deallocation is called in the dll (not in exe-file) in the second case?
2) Does the second case work well if exe-file and dll was compiled with different compilers (or different settings).
An answer to your first question: The virtual destructor in your dll is called - the information about its location is embedded in your object (in the vtable). In the case of memory deallocation it depends how disciplined the users of your IBase are. If they know they have to call Release() and consider that exception can bypass the control flow in an surprising direction, the right one will be used.
But if CreateInterface() returns shared_ptr<IBase> it can bind the right deallocation function right to this smart pointer. Your library may look like this:
Destroy(IBase* p) {
... // whatever is needed to delete your object in the right way
}
boost::shared_ptr<IBase> CreateInterface() {
IBase *p = new MyConcreteBase(...);
...
return shared_ptr<IBase>(p, Destroy); // bind Destroy() to the shared_ptr
} // which is called instead of a plain
// delete
Thus every user of your DLL is easily prevented against resource leaks. They never have to bother about calling Release() or pay attention to exceptions bypassing surprisingly their control flow.
To answer your second question: The downside of this approach is clearly stated by the other answers: You're audience has to use the same compiler, linker, settings, libraries as you. And if they could be quite a lot this can be major drawback for your library. You have to choose: Safety vs. larger audience
But there's a possible loophole: Use shared_ptr<IBase>in your application, i.e.
{
shared_ptr<IBase> p(CreateInterface(), DestroyFromLibrary);
...
func();
...
}
Thus no implementation specific object is passed across the DLL boundary. Nevertheless your pointer is safely hidden behind the shared_ptr, who's calling DestroyFromLibrary at the right time even if func()'s throwing an exception or not.
I would advise against using shared_ptr in the interface. Even using C++ at all in the interface of a DLL (as opposed to "extern C" only routines) is problematic because name-mangling will prevent you from using the DLL with a different compiler. Using shared_ptr is particularly problematic because, as you have already identified, there is no guarantee that the client of the DLL will use the same implementation of shared_ptr as the caller. (This is because shared_ptr is a template class and the implementation is contained entirely in the header file.)
To answer your specific questions:
I'm not quite sure what you are asking here... I'm assuming that your DLL will contain implementations of classes derived from IBase. The code for their destructors (as well as the rest of the code) will, in both of your cases, be contained in the DLL. However, if the client initiates the destruction of the object (by calling delete in the first case or by letting the last instance of the shared_ptr go out of scope in the second case), then the destructor will be called from client code.
Name-mangling will usually prevent your DLL from being used with a different compiler anyway... but the implementation of shared_ptr may change even in a new release of the same compiler, and that can get you into trouble. I would shy away from using the second option.
Using shared_ptr will make sure the resource releasing function will be called in the DLL.
Have a look at the answers to this question.
A way out of this problem is to create a pure C interface and a thin fully inlined C++ wrapper around it.
On your first question: I'm taking an educated guess and not speaking from experience, but it seems to me that the second case the memory deallocation will be called "in the .exe". There are two things that happen when you call delete object;: first, destructors are called and second, the memory for the object is freed. The first part, destructor calling, will definitely work as you expect, calling the right destructors in your dll. However, since shared_ptr is class template, its destructor is generated in your .exe, and therefore it will call operator delete() in your exe and not the one in the .dll. If the two were linked against different runtime versions (or even statically linked against the same runtime version) this should lead to the dreaded undefined behavior (this is the part I'm not entirely sure about, but it seems logical to be that way). There's a simple way to verify if what I said is true - override the global operator delete in your exe, but not your dll, put a breakpoint in it and see what's called in the second case (I'd do that myself, but I have this much time for slacking off, unfortunately).
Note that the same gotcha exist for the first case (you seem to realize that, but just in case). If you do this in the exe:
IBase *p = CreateInterface();
delete p;
then you are in the same trap - calling operator new in the dll and calling operator delete in the exe. You'll either need a corresponding DeleteInterface(IBase *p) function in your dll or a Release() method in IBase (which doesn't have to be virtual, just not make it inline) for the sole purpose of calling the right memory deallocation function.