Reputation: 73
The following code makes my program crash (program exits) by heap corruption when the third line (the 'delete' command) is called:
1: CStringArray* pStringArray = new CStringArray();
2: ClassInDll::addToStringArray(_T("asdf"), *pStringArray);
3: delete pStringArray;
with
1: ClassInDll::addToStringArray(CString s, CStringArray& sa){
2: sa.Add(s);
3: }
addToStringArray() is static
Be aware that this is not actually my code, but simply the minimum with which I can reproduce the error. It is reproducible with CArray<CString> as well.
I verified, that the heap corruption does indeed not happen before that code line via
gflags /p /enable MyExe.exe /full
StackTrace:
Dll dependency | MFC source | ||
---|---|---|---|
1 | CStringArray creation | MyExe.exe > MFC | ...\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc\array_s.cpp |
2 | Internal array allocation | MyExe.exe > MyDll.dll > MFC | ...\Microsoft Visual Studio 10.0\VC\atlmfc\include\afxcoll.inl |
3 | Deletion | MyExe.exe > MFC | ...\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc\array_s.cpp |
The fact that the internal array is not deleted the same way it was created is probably the error. (Please correct me if I'm wrong)
I made sure that the same MFC settings are used in MyExe.exe as well as MyDll.dll, i.e.:
Use of MFC | Use MFC in a Shared DLL |
Use of ATL | Not using ATL |
Character Set | Use Unicode Character Set |
I test in debug mode, so there is no optimization.
MyDll.dll is not the only dll that is loaded, and there is too much going on with project dependencies (to third party dlls etc), so I cannot make all this part of my question.
So my questions boil down to:
I have tried turning it off and on again ;)
Thank you in advance!
PaulMcKenzie pointed out that this is the case if I build against different CRTs which was the case. One was "Multithreaded Debug DLL", the other was "Multithreaded DLL". Still, the problem persists, after making both equal. This page states that if using VS 2015 and above with Windows 10 and having project settings so that the same runtime library is used, the same CRT library is used at runtime (and therefore should use the same heap, right?).
I've made sure, that every entry within "Project Properties -> C/C++ -> Code Generation" is exactly the same in the exe and dll.
Upvotes: 4
Views: 640
Reputation: 73
It turned out that release and debug dlls were both being loaded (because of another dll):
The "modules" window sure does help, if you only know that you should look there.
Thanks to PaulMcKenzie and IInspectable for leading me into the right direction.
Upvotes: 1
Reputation: 51845
Passing MFC objects (even via pointers) between modules (EXEs and DLLs, or different DLLs) is a very tricky business. If you're simply using classes in the DLL, then you should (at the very least) be using the AFX_MANAGE_STATE
macro (see here) in the DLL.
However, if your DLL is defining its own MFC-derived classes (your ClassInDll
seems to be such), it should really be built as an MFC Extension DLL.
The whole process of building extension DLLs (and even using the 'regular' MFC DLLs) is rather too broad for me to provide any usable source code for you here. But, from the second link above, the following section is likely relevant to the problem(s) you are seeing (bold italics are mine):
Memory Management
MFCx0.dll and all MFC extension DLLs loaded into a client application's address space use the same memory allocator, resource loading, and other MFC global states as if they were in the same application. This is significant because the non-MFC DLL libraries and the regular MFC DLLs do the exact opposite and have each DLL allocating out of its own memory pool.
If an MFC extension DLL allocates memory, that memory can freely intermix with any other application-allocated object. Also, if an application that dynamically links to MFC fails, the protection of the operating system maintains the integrity of any other MFC application sharing the DLL.
Similarly other global MFC states, like the current executable file to load resources from, are also shared between the client application and all MFC extension DLLs as well as MFCx0.dll itself.
Upvotes: 2