Dll Heap Vs Exe Heap

I have created a DLL, and an EXE which uses that DLL. If the Dll allocates memory using new, then the executable takes the pointer to this memory and attempts to deallocate it using delete, I get a debug assertion ( _ASSERTE(_CrtIsValidHeapPointer(pUserData)); on line 1044 of dbgheap.c ), to do with the fact that the memory I am attempting to deallocate is not from my heap, which it must be. Obviously the DLL and the EXE have separate heaps, and hence memory allocated by the DLL cannot be deleted by the EXE. I require that the EXE be able to delete memory the DLL allocated, how do I do this?

I am using visual c++ 6.0, both the dll and executable are debug builds.
Below is my test code fragment to demonstrate the problem:

// the dll is a win32 non-MFC DLL
//heaptest.h, in the dll
class MyClass;

class HEAPTEST_API MyClass
{
public:
  MyClass();
  ~MyClass();
  void Add();
  MyClass *Remove();
  MyClass *pChild;
};

// heaptest.cpp, in the dll
#include "stdafx.h"
#include "dllheap.h"

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                               )
{
  switch (ul_reason_for_call)
  {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:            break;
    }
  return TRUE;
}

MyClass::MyClass()
{
  pChild = NULL;
}

MyClass::~MyClass()
{
  if( pChild )
    delete pChild;
}

void MyClass::Add()
{
  if( pChild ) // has no child, tell the child to add one
    pChild->Add();
  else             // no child, add one
    pChild = new MyClass();
}

MyClass *MyClass::Remove()
{
  MyClass *pCh = pChild;
  pChild = NULL;
  return pCh;
}

// test.cpp, in the executable. This is an MFC app.
MyClass *m = new MyClass();
m->Add();
MyClass *pmc = m->Remove();
delete m;
if( pmc )
  delete pmc; // the dll heap allocated it, see if I can delete it. This causes the debug assertion.
frogpasswordAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

MadshiCommented:
I'm a Delphi programmer, but it's the same with Delphi. If you use the internal memory functions (which are optimized) you have this problem, because the exe and the dll each have their own memory manager.
One solution in Delphi is to import a specific memory manager dll, so that both the exe and your dll use this memory manager dll. I don't know, perhaps there's the same possibility for C, too.
Otherwise you can always use the win32 memory functions like LocalAlloc, GlobalAlloc, VirtualAlloc, ... These should solve all your problems.

Regards, Madshi.
0
MadshiCommented:
Ooops, on the second look I see, we're talking about classes, not about "normal" pointers. That's a bit different. I can only tell again, how it is in Delphi: There you can overwrite the functions which are responsible to allocate the classes memory. You should then use one of the win32 API functions instead of the C++ ones.
If this all doesn't help you, you should reject my answer, since I can't tell you much more than this.

Regards, Madshi.
0
nietodCommented:
In C and C++ you can compile the DLL and the EXE to use the "DLL version of the run-time library (RTL) instead of the statically linked version of the RTL.  This will eliminate this problem, and actually other problems as well.  
0
CompTIA Network+

Prepare for the CompTIA Network+ exam by learning how to troubleshoot, configure, and manage both wired and wireless networks.

nietodCommented:
Here's an answer gave from another question on this topic, it describes what to do in VC.  

The problem is that if the EXE and DLL use the staticly linked version of the run-time library (RTL), they each have their own seperate copies of the RTL.  These copies each have thier own seperate heaps for allocating memory with the new operator.   The problem is that each one does not "know" about the other.  So for example, if the DLL allocates memory, the memory comes from the heap in the DLL's copy of the RTL.  If a pointer to that memory is passed back to the EXE (it may be passed in a subtle way, like inside a class) and if that EXE later makes changes that require that the memory specified by the pointer be deleted, then the EXE will try to delete the memory, but will not be able to find the memory inside its heap.  This is is because the memory did not come from the heap.  Hence the problem.

The solution is to have the EXE and all the C++ DLLS that it uses link with the DLL version of the RTL.  Then the EXE and all the DLLS will share a single copy of the run-time library and will therefore share a single heap.

To set this in VC:

"Project" menu
"Settings..." menu item
in the dialog box that appears  "C/C++" tab
"Code generation" Category
in "Use run-time library:" select one of the DLL options.

(There are two DLLoptions there, one for a debug version, one for a release version.  Make sure you choose the setting that is right for the version you are creating)

Note that these settings need to be changed for EVERY version (debug. release etc) of the EXE and and DLLs that is shares memory with.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
frogpasswordAuthor Commented:
The comment from nietod is a useable response, if set as an answer it will most probably be accepted (just need to try it out first).
0
chensuCommented:
nietod is right. This question has been discussed several times.

Another way (I would prefer) is to add a wrapper function to your DLL, which deletes the memory block the DLL allocates. In your EXE, call this function instead of using delete directly.
0
nietodCommented:
Why would you prefer that?  You may end up having 100s of these wrapper functions.  Besides it can't fix all cases.  Like if this occurs inside an STL class.
0
chensuCommented:
>You may end up having 100s of these wrapper functions.

You may write only one wrapper function by passing the pointer.

void FreeMem(void *p)
{
    delete p;
}

>Besides it can't fix all cases.  Like if this occurs inside an STL class.

Agree. But it is sufficient in some cases.
0
nietodCommented:
But that delete doesn't work if the object has destructors.   I'm sort of surprised you prefer that.  Is there some dissadvantage to the DLL versio of the RTL that you are trying to avoid?
0
chensuCommented:
Well, sometimes I just want to avoid to distribute the DLLs. There is no major disadvantage.
0
nietodCommented:
I can agree with that.  Especially when a computer has an older copy of the DLLs installed and in use.  Upgrading can be a pain in that case.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.