From 4f66f33a09a4bd82c513d12edcd345e8ff9f68e5 Mon Sep 17 00:00:00 2001 From: Hoppy Date: Fri, 11 Dec 2015 09:07:17 -0600 Subject: [PATCH] Demonstrate a Static Initialization problem in Visual C++ 2015 --- example/DllLoader/DllLoader.cpp | 8 +++-- example/SampleDLL/SampleDLL.cpp | 58 +++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/example/DllLoader/DllLoader.cpp b/example/DllLoader/DllLoader.cpp index 3fda631..4eac43a 100644 --- a/example/DllLoader/DllLoader.cpp +++ b/example/DllLoader/DllLoader.cpp @@ -9,7 +9,7 @@ typedef int (*addNumberProc)(int, int); -#define DLL_FILE TEXT("..\\SampleDLL\\SampleDLL.dll") +#define DLL_FILE TEXT("..\\SampleDLL\\Debug\\SampleDLL.dll") void LoadFromFile(void) { @@ -100,8 +100,12 @@ void LoadFromMemory(void) int main(int argc, char* argv[]) { - LoadFromFile(); + // Oddly, doing this first seems to make the load from memory work + //OutputDebugString("Loading from File\n"); + //--> LoadFromFile(); + printf("\n\n"); + OutputDebugString("Loading from Memory\n"); LoadFromMemory(); return 0; } diff --git a/example/SampleDLL/SampleDLL.cpp b/example/SampleDLL/SampleDLL.cpp index 7bf03ef..57e64dd 100644 --- a/example/SampleDLL/SampleDLL.cpp +++ b/example/SampleDLL/SampleDLL.cpp @@ -1,9 +1,67 @@ #include "SampleDLL.h" +#include + + +#include +#include +#include +using namespace std; + + +// adding this class to track instantiations +class FunnBall { +public: + FunnBall(const char* ident) + : _ident(ident){ + ostringstream msg; + msg << "Hi, I'm in the constructor for FB ident: " << _ident << endl; + OutputDebugString(msg.str().c_str()); + } + const string& ident() const { return _ident; } +private: + string _ident; +}; + +// module static, this always seems to work. +// they end up happening in the c++ runtime as part of DllMain +static FunnBall fb1("This is the module static"); + +// make a function that has static objects inside it +static void havefun() { + + // these guys are required to be initialized before first use by c++ + // They fail to properly initialize with MemoryLoader + // Looking (with very rusty eyes) at the assembler, it appears that VC + // is trying to do this trick by writing a conditional so that it can test + // if it is the first-time through the function, and then doing the initialization + // only once. It works with LoadLibrary, but not MemoryLoader. + // the thing being examined (if you look at the assembler) is a location that + // is initialized with DD dup(?), which makes no immediate sense. So I'm guessing + // that something else in the load process is initializing this DWORD in the LoadLibrary + // case. + static FunnBall fb2("This is the static in the function"); + static unordered_map damap = { + {"one", "wun"}, + {"two", "too"} + }; + + ostringstream msg; + msg << "idents in play: fb1=" << fb1.ident() << ", fb2=" << fb2.ident() + << ", map has " << damap.size() << endl; + OutputDebugString(msg.str().c_str()); + + if (damap.size() != 2) { + OutputDebugString("============== FAIL ==============\n"); + } +} + extern "C" { SAMPLEDLL_API int addNumbers(int a, int b) { + // force our test function to run. + havefun(); return a + b; }