Inconsistent operator new/delete calling - c++

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.

Related

Point of code execution in C++ and shared libraries

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).

Deleting objects pointed to by smart pointers

In my code I have a SoundManager class, which contains and operates on all the sounds for my game. This class needs to be instantiated and it's methods called by multiple other classes. However I wish for there only to be one set of sounds occupying memory, so in the interest of efficiency all of the assets are declared as static shared_ptrs.
#include "SoundManager.h"
static shared_ptr<ISoundEngine> sEngine;
static shared_ptr<ISoundSource> hoverSound;
static shared_ptr<ISoundSource> confirmSound;
static shared_ptr<ISoundSource> mainBGM;
static shared_ptr<ISound> bgmInterface;
SoundManager::SoundManager(void)
{
//first we need to create the irrKlang sound engine instance
if(!sEngine)
{
sEngine.reset(createIrrKlangDevice());
}
if(!hoverSound)hoverSound.reset(sEngine->addSoundSourceFromFile("Sounds/ButtonHover.mp3"));
if(!confirmSound)confirmSound.reset(sEngine->addSoundSourceFromFile("Sounds/ButtonConfirm.mp3"));
if(!mainBGM)mainBGM.reset(sEngine->addSoundSourceFromFile("Sounds/mainBGM.mp3"));
//set some default volumes
hoverSound->setDefaultVolume(1.0f);
confirmSound->setDefaultVolume(0.4f);
mainBGM->setDefaultVolume(0.5f);
}
SoundManager::~SoundManager(void)
{
}
This SoundManager is instantiated in my main() function and every time i need to load the title-screen (SoundManager is instantiated in this titlescreen class too). Initialising and destroying the title-screen over and over do not cause a problem. The static shared_ptrs objects are not destroyed as they are still in use by the main functions instance of SoundManager.
Now this all works fine in practice for running my game. However when it comes to exiting cleanly, when the static objects above are dismantled, unhandled runtime exceptions (access violations) are thrown at me. With VS2012's debugger pointing me to a line in memory.h.
private:
virtual void _Destroy()
{ // destroy managed resource
delete _Ptr; <<<<<<<<<The debugger points to this line
}
I was to understand that similar to obj-c, c++ shared_ptrs use reference counters to ensure that the objects aren't deleted until no object exists that require their use any more. I don't understand what could be causing these errors.
Maybe an important part I shouldn't omit: My game is exited via a call to exit(0); as close to the main() function as possible. I haven't taken any sort of action to cleanup the SoundManagers members before doing this, as I thought the shared_ptr's handled this.
Does anybody know what could be causing my cleaning up problem?
If you want to manually free a resource used by a shared_ptr you need to call reset. As for using static shared_ptr I don't think I get the reasoning. The whole point is that they do not copy of the resource around, so you will only have one resource.
Your are using the IRRKLang library. This library comes as a precompiled binary (dll if you are on windows). This library makes itself binary compatible by using pure virtual bases. This works, but you cannot delete an object for a library like that, because your program new/delete are different from the new/delete of the library. Those type of libraries provide a way to deallocate the memory, this this case drop.
To use shared_ptr etc you have to use a custom deleter. Take a look at Using custom deleter with std::shared_ptr to see how to do it and modify it to your own needs.
In your case since you are using Visual Studio 2012 you can probably do something like this
template<class T>
struct IrrDeleter{
void operator()(T* t){
t->drop();
}
};
then change all your reset lines to include the deleter, for example
sEngine.reset(createIrrKlangDevice(),IrrDeleter<ISoundEngine>());

operator "new" returning a non-local heap pointer for only one class?

Language : C++
Platform : Windows Server 2003
I have an exe calling a DLL.
EDIT :
(exe is not doing anything, it calls few global function which does everything related to DLL within DLL. It does not explicitly new any of DLL classes)
I allocate (new) the memory for class A within the DLL, it returns me a non-local heap pointer.
I tried to new other classes within the DLL (which are in DLL), "new" returns a valid heap pointer for them, its only Class A which is not being allocated properly.
I am on windows and validating the heap by this function call :
EDIT:
ClassA* pA = new ClassA();
_CrtIsValidHeapPointer ( (const void *) pA )
I am seriously confused why this only happens with new-ing Class A and no other class ?
(All Native Code)
FINAL EDIT :
it turned out to be a bad build. can't get it to reproduce in the new one... wasted 5 days on this :'(
Export only global functions from DLLs and call only exported functions and through v-tables. Your problem is only one of many caused by trying to export entire classes. DLLs aren't the same as .so libraries.
EDIT: Since the question now reveals that the class isn't exported, but all of this is observed inside the single DLL, going to suggest other possible causes.
Is the same pointer returned from new being tested, or could it be a pointer to a base sub-object? Did the allocation use new or new []? Either of these could cause the pointer to point into the middle of a heap block instead of the start.
If Class A overrides operator new then the memory for that class could be allocated in the DLL's copy of the C runtime. This would cause _CrtIsValidHeapPointer to return false - because your version of the C runtime library is using a different heap than the one in the DLL.
The value returned from _CrtIsValidHeapPointer is generally not reliable anyway (certainly, even though it may return TRUE it doesn't necessarily mean you can use the pointer). Why do you do this anyway?
Perhaps the class declares its own operator new that get storage from some mystery location?
e.g. The author of the class may have written:
class MyClass {
public:
void * operator new (size_t amt);
void operator delete(void *);
};
Then their operator new beats your operator new.
Either that or the DLL is built with /MTd while the executable uses /MD.

Problem retuning a vector from a c++ dll to another c++ exe

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.

Using shared_ptr in dll-interfaces

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.