I have a DLL that is being loaded at run-time. The DLL relies on a static variable for internal workings (it is a std::map), this variable is defined within the DLL.
When I call the first function from the DLL after loading, I get a SegFault from the DLL, the map was never initialized. From everything I have read from DLL Loading, static and global data initialization should happen before even the call to DLLMain.
To test static initialization I added a static struct that prints out a message, and even threw in a breakpoint for good measure.
static struct a
{
a(void) { puts("Constructing\n"); }
}statica;
There was no message, or break before DLLMain or the function is called.
Here is my loading code:
dll = LoadLibrary("NetSim");
//Error Handling
ChangeReliability = reinterpret_cast<NetSim::ChangeReliability>
(GetProcAddress(dll, "ChangeReliability"));
ChangeReliability(100);
I have verified that the dll version is the correct one, rebuilt the entire project multiple times, but no difference. I am fresh out of ideas.
Actually, chances are you are making a wrong assumption:
See item 4 of Effective C++:
The reason is that ensuring a "correct" initialization order is impossible, and therefore the C++ standard simply gives up on it, and just leave that as undefined.
So, if your DllMain is in a different file than the code where the static variable is declared, the behavior is undefined, and you have very good chances of getting DllMain called before the initialization is actually done.
Solution is quite simple, and outlined in the same item of Effective C++ (btw: I strongly recommend you reading that book!), and requires declaring the static variable inside a function, that simply returns it.
The "classic" simple singelton implemention will work:
Of course, you shouldn't call this from DllMain.
I'd like to point out that complex static objects in DLLs should be avoided.
Remember that static intializers in a DLL are called from DllMain, and thus all restrictions on DllMain code apply to constructors and destructors of static objects. In particular, std::map can allocate dynamic memory during construction, which can lead to unpredictable results if C++ runtime is not initialized yet (in case you are using dynamically-linked runtime).
There is a good article on writing DllMain: Best Practices for Creating DLLs.
I would suggest changing your static map object to a static pointer (which can be safely zero-initialized), and either adding a separate DLL-exported function for initialization, or using lazy initialization (i.e. check the pointer before accessing it and create the object if it's null).
Although I'm not sure why initialization fails, one workaround would be to explicitly create and initialize the variables in your DllMain. As per Microsoft's best practices paper, you should avoid using CRT allocation function in DllMain, so I use windows heap allocation functions instead, with a custom allocator (note: untested code, but should be more or less right):
When you linked your DLL, was the /ENTRY switch specified? If so, it'll override the linker's default which is DllMainCRTStartup. As a result, _CRT_INIT won't be called and, in turn, the global initializers won't be called which will result in uninitialized global (static) data.
If you are specifying /ENTRY for your own entry point, you need to call _CRT_INIT during process attach and process detach.
If you are not specifying /ENTRY, the linker should be using the CRT's entry point which calls _CRT_INIT on process attach/detach before calling into your DllMain.