0
votes

Background: I have a large legacy C++ application with an MFC UI. I am trying to refactor the project and migrate it to a new .Net UI. Right now as an initial step I am trying to refactor the MFC exe project in Visual Studio 2015, into an regular MFC dll which I can invoke from an exe project. (see below) Gradually we plan move the UI from MFC to .Net. We are trying to change the engine while the plane is in the air...

Anyway I am having trouble with the various statics and globals in the legacy C++ application. When I load the new dll into an exe, I get an exception with an access violation. Turns out the heap is not being created correctly inside the dll and I dont understand why....

I narrowed the problem down to a very simple struct with a file level static variable. The variable invokes the constructor on library load before normal application logic.

In SomeData.cpp in MfcDll project

struct SomeData {
    SomeData()
    {
        ::OutputDebugString("construct data\n");
        char* mem = new char[10]; // nope
        if (mem)
        {
            ::OutputDebugString("got mem\n");
        }
        else
        {
            ::OutputDebugString("no heap\n");
        }
    }
};

SomeData fileLevelStatic;

The output is:

construct data
no heap

This is my callstack when I breakpoint the constructor

MfcDll.dll!SomeData::SomeData() Line 57 C++
MfcDll.dll!`dynamic initializer for 'fileLevelStatic''() Line 63    C++
ucrtbased.dll!00007ffdc88f947d()    Unknown
MfcDll.dll!dllmain_crt_process_attach(HINSTANCE__ * const instance, void * const reserved) Line 67  C++
MfcDll.dll!dllmain_crt_dispatch(HINSTANCE__ * const instance, const unsigned long reason, void * const reserved) Line 133   C++
MfcDll.dll!dllmain_dispatch(HINSTANCE__ * const instance, const unsigned long reason, void * const reserved) Line 190   C++
MfcDll.dll!_DllMainCRTStartup(HINSTANCE__ * const instance, const unsigned long reason, void * const reserved) Line 249 C++
ntdll.dll!00007ffe005da35f()    Unknown

So what am I doing wrong here? What do I need to do ensure I have a heap available to static objects. The legacy app makes extensive use of statics and globals. Yes we would like to refactor those but it huge task so we need to maintain it working while we do that...

Also to verify its not a .Net vs MFC thing, I am doing this particular test in a solution with only C++. I have the MFCDll, legacy statically linked C++ libraries and a stock Window Application project also in C++ which references MFCDll. So .Net is not even in the code at this point... its all C++ with MFC and Windows.

2
Is your complete project using the same runtime support version and memory model?Richard Critten
What are static constructors?πάντα ῥεῖ
In the solution project properties, All projects (static libs, the dll and the exe project) all use "Multi-threaded Debug DLL (/MDd)" The dll is set to "Use MFC in a Shared DLL"meissnersd
"static constructors" perhaps I said it wrong. The constructors of static objects, which in some cases need to do complicated things and access the heap, are the problem. So SomeData fileLevelStatic; invokes the constructor SomeData::SomeData() prior to application codemeissnersd

2 Answers

1
votes

It turns out that the legacy code has locally overridden ::operator new() and it was doing something complicated, that was now broken. It was particularly confusing because I had a break point on the line
char* mem = new char[10];

and F11 did not step into the local implementation of new until I actually put a break point inside of the new() function.

So basically a home made foot gun... sigh. Thanks for the help.

0
votes

The constructor is called during load time of the dll. Maybe the heap isn't yet even initialized for the dll by that time.

The correct place for initialization code would be InitInstance and ExitInstance or DllMain, where you also can do the cleanup. Move your constructor and destructor code there.