DLL/App Memory Allocation
-
Hi! A dynamically loaded DLL I wrote receives a pointer to a class that I pass to it from the client app. A certain method in that class, (let's call it) cClass::AllocMem()is called inside the DLL to allocate some memory. The "problem" is that the allocated memory is stored on the heap of the DLL, as opposed to the heap of the client app, which is where I'd like it to reside. Is there any way for me to still be able to call this AllocMem() method inside the DLL and have the memory allocated inside the client app's heap? This is just a plain vanilla Win32 application and DLL. I know in MFC, there the AFX_MANAGE_STATE() macro to help out with these things, but it is unavailable to me. Does anybody have any ideas? Thanks a bunch! Steve The Plant
-
Hi! A dynamically loaded DLL I wrote receives a pointer to a class that I pass to it from the client app. A certain method in that class, (let's call it) cClass::AllocMem()is called inside the DLL to allocate some memory. The "problem" is that the allocated memory is stored on the heap of the DLL, as opposed to the heap of the client app, which is where I'd like it to reside. Is there any way for me to still be able to call this AllocMem() method inside the DLL and have the memory allocated inside the client app's heap? This is just a plain vanilla Win32 application and DLL. I know in MFC, there the AFX_MANAGE_STATE() macro to help out with these things, but it is unavailable to me. Does anybody have any ideas? Thanks a bunch! Steve The Plant
Have you tried declaring
cClass::AllocMem()
as virtual? Joaquín M López Muñoz Telefónica, Investigación y Desarrollo -
Have you tried declaring
cClass::AllocMem()
as virtual? Joaquín M López Muñoz Telefónica, Investigación y DesarrolloWell, I tried and it worked! But I don't understand why. Does it have anything to do the class' virtual table when you pass it to the DLL? Steve The Plant
-
Well, I tried and it worked! But I don't understand why. Does it have anything to do the class' virtual table when you pass it to the DLL? Steve The Plant
Well, actually it's magic ;P Now seriously, what's happening here is this: Both your client app and your DLL are having access to
cClass.h
andcClass.cpp
, and both modules are subsequently compiling and linking their own copies ofcClass::AllocMem()
. Now, when you pass a pointer to acClass
object created by the app to the DLL, and the DLL code executespcClass->AllocMem()
, what it is actually doing is invoking its own version ofcClass::AllocMem()
againstpcClass
: crash promptly ensues when the clients tries to free the memory allocated, for the reasons you already diagnosed. Now, if you makecClass::AllocMem()
virtual, then the DLL does not execute any local version of the method, but instead usespcClass
to locate its associated virtual table andAllocMem()
implementation, both of which reside at the app's home (which originally created the object). Having things arranged like this, you can even removecClass.cpp
from the DLL build and things will still work as long as the DLL limits itself to handlecClass
pointers passed from the app, and all relevant methods are virtualized. This is also a good thing to have in the light of OO, as it defines an interface contract between the app and the DLL and allows you to change the implementation code without the DLL knowing nor having to be recompiled. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo -
Well, actually it's magic ;P Now seriously, what's happening here is this: Both your client app and your DLL are having access to
cClass.h
andcClass.cpp
, and both modules are subsequently compiling and linking their own copies ofcClass::AllocMem()
. Now, when you pass a pointer to acClass
object created by the app to the DLL, and the DLL code executespcClass->AllocMem()
, what it is actually doing is invoking its own version ofcClass::AllocMem()
againstpcClass
: crash promptly ensues when the clients tries to free the memory allocated, for the reasons you already diagnosed. Now, if you makecClass::AllocMem()
virtual, then the DLL does not execute any local version of the method, but instead usespcClass
to locate its associated virtual table andAllocMem()
implementation, both of which reside at the app's home (which originally created the object). Having things arranged like this, you can even removecClass.cpp
from the DLL build and things will still work as long as the DLL limits itself to handlecClass
pointers passed from the app, and all relevant methods are virtualized. This is also a good thing to have in the light of OO, as it defines an interface contract between the app and the DLL and allows you to change the implementation code without the DLL knowing nor having to be recompiled. Joaquín M López Muñoz Telefónica, Investigación y DesarrolloWaitasecond! According to Richter there is no such thing as a local DLL heap in Win32. The DLL uses the heap of the client process. So unless the DLL in question here creates it's own heap using HeapCreate then the OP's problem cannot be caused by allocation of different heaps. Cheers Steen. "To claim that computer games influence children is rediculous. If Pacman had influenced children born in the 80'ies we would see a lot of youngsters running around in dark rooms eating pills while listening to monotonous music"
-
Waitasecond! According to Richter there is no such thing as a local DLL heap in Win32. The DLL uses the heap of the client process. So unless the DLL in question here creates it's own heap using HeapCreate then the OP's problem cannot be caused by allocation of different heaps. Cheers Steen. "To claim that computer games influence children is rediculous. If Pacman had influenced children born in the 80'ies we would see a lot of youngsters running around in dark rooms eating pills while listening to monotonous music"
All right all right. The picture is larger than I showed, but, taken literally, Richter is wrong. What is causing these problems with allocating memory on one side and deallocating at the other is the C runtime library (CRT) used by each of the parts. As you know, the CRT comes in six flavors:
- (Release) Single-Threaded
- (Release) Multithreaded
- (Release) Multithreaded DLL
- Debug Single-Threaded
- Debug Multithreaded
- Debug Multithreaded DLL
Let's begin with the debug/release aspect. In debug mode, standard C/C++ functions like
malloc()
andnew
allocate, when requested a memory block, additional info about the block than can be later used to identify out of bounds errors and stuff like that. This info is stored contiguously to the block delivered to the app, so that whenfree()
ordelete
are invoked, these functions know where the info should be with respect to the pointer to deallocate. Now, if your app uses a debug CRT and the DLL a release one, and the DLLmalloc()
s some memory and the app tries tofree()
it, a crash will follow as the debug CT cannot find that additional info I talked about. Other similar scenarios involving debug/release mixing follow analogous patterns. Now for the DLL/not DLL option. If you choose not DLL, then the CRT is linked as a static library to your app (or DLL). The CRT maintains a private heap (yes, it does) called_crtheap
which is created upon initiation of the app (or the DLL). So, even if you use the exact same version of CRT in static mode for your app and your DLL, your final executable will end up with two_crtheap
s accessed respectively from the app CRT and the DLL CRT code. As before, allocating on one side and deallocating on the other leads to catastrophe. Enough is enough. It is simple to check that all combinations of CRTs exhibit this problem except if both the app and the DLL use the same CRT version and this CRT is linked as a DLL. Then, only one_crtheap
exists, shared by all folks in the program, and all other aspects being equal (debug/release, multithreaded/single threaded) things run smooth. The moral of the story: Expect problems when passing around the responsibility of freeing a CRT-allocated chunk of memory except if you are 100% sure all parts involved (app, DLLs) use the same CRT version and this is linked dynamically. Joaquín M López Muñoz Telefónica, Investigación y Desarrollo -
All right all right. The picture is larger than I showed, but, taken literally, Richter is wrong. What is causing these problems with allocating memory on one side and deallocating at the other is the C runtime library (CRT) used by each of the parts. As you know, the CRT comes in six flavors:
- (Release) Single-Threaded
- (Release) Multithreaded
- (Release) Multithreaded DLL
- Debug Single-Threaded
- Debug Multithreaded
- Debug Multithreaded DLL
Let's begin with the debug/release aspect. In debug mode, standard C/C++ functions like
malloc()
andnew
allocate, when requested a memory block, additional info about the block than can be later used to identify out of bounds errors and stuff like that. This info is stored contiguously to the block delivered to the app, so that whenfree()
ordelete
are invoked, these functions know where the info should be with respect to the pointer to deallocate. Now, if your app uses a debug CRT and the DLL a release one, and the DLLmalloc()
s some memory and the app tries tofree()
it, a crash will follow as the debug CT cannot find that additional info I talked about. Other similar scenarios involving debug/release mixing follow analogous patterns. Now for the DLL/not DLL option. If you choose not DLL, then the CRT is linked as a static library to your app (or DLL). The CRT maintains a private heap (yes, it does) called_crtheap
which is created upon initiation of the app (or the DLL). So, even if you use the exact same version of CRT in static mode for your app and your DLL, your final executable will end up with two_crtheap
s accessed respectively from the app CRT and the DLL CRT code. As before, allocating on one side and deallocating on the other leads to catastrophe. Enough is enough. It is simple to check that all combinations of CRTs exhibit this problem except if both the app and the DLL use the same CRT version and this CRT is linked as a DLL. Then, only one_crtheap
exists, shared by all folks in the program, and all other aspects being equal (debug/release, multithreaded/single threaded) things run smooth. The moral of the story: Expect problems when passing around the responsibility of freeing a CRT-allocated chunk of memory except if you are 100% sure all parts involved (app, DLLs) use the same CRT version and this is linked dynamically. Joaquín M López Muñoz Telefónica, Investigación y DesarrolloWow! You really do know what you're talking about, don't you? I stand corrected, I bow my head before you ;-) I did a search on MSDN on the subject (yeah, I know, should have done it before), and article Q190799 does a pretty good job explaining things (at least after I had read your post first :-) I will immidiately check if my current multi-DLL application project is linked to the MT DLL version! Cheers Steen. "To claim that computer games influence children is rediculous. If Pacman had influenced children born in the 80'ies we would see a lot of youngsters running around in dark rooms eating pills while listening to monotonous music"