我们在VS2015中有一个大型解决方案,它有两个库和许多用于测试我们应用程序的win32项目。我们的项目及其依赖关系如下:
这些库最初是静态的,但我们将它们转换为DLL以便更快地进行链接。我用__declspec(dllexport)
装饰器修改了我们的应用程序代码,并成功编译并链接我们的应用程序作为DLL。所有不使用eventLibrary.lib
并且成功运行的测试用例,其余的崩溃因为eventLibrary.lib
在appLibrary.dll
和testCase.exe
中静态连接。
我将eventLibrary.lib
转换为DLL,它与我们的exes构建并链接,但在它们到达main
之前崩溃。我正在使用def文件而不是修改库源。如果我从eventLibrary.dll
中删除testCase.exe
依赖项并从appLibrary.dll
导出其符号,则会发生完全相同的崩溃。
崩溃是在ostream
超载的<<
运营商内部。传入的stringstream
(下面的参数_Ostr
)与使用静态库构建时相同。我得到一个0xC0000005: Access violation executing location 0x0D20E4E9
,这似乎是由调用width
方法引起的:
template<class _Traits> inline
basic_ostream<char, _Traits>& operator<<(
basic_ostream<char, _Traits>& _Ostr,
const char *_Val)
{ // insert NTBS into char stream
typedef char _Elem;
typedef basic_ostream<_Elem, _Traits> _Myos;
ios_base::iostate _State = ios_base::goodbit;
streamsize _Count = (streamsize)_Traits::length(_Val); // may overflow
streamsize _Pad = _Ostr.width() <= 0 || _Ostr.width() <= _Count
? 0 : _Ostr.width() - _Count; // <- Dies here
这发生在Google Test框架中的全局变量初始化过程中,该框架仍然是一个静态库。调用堆栈如下:
testCase.exe!testing :: Message :: operator <<(const char [7]&val)第131行testCase.exe!testing :: internal :: FlagToEnvVar(const char * flag)第1136行testCase.exe!testing :: internal :: BoolFromGTestEnv(const char * flag,bool default_value)第1195行testCase.exe!testing ::`'FLAGS_gtest_also_run_disabled_tests'的动态初始化程序'()第202行
动态链接我们的事件库以某种方式破坏testCase.exe
中的内存?这有没有与拥有自己的堆的DLL有关?我确保在构建和链接时使用相同的运行时(/MDd
)和相同的标志编译我们的DLL和exes。
我通过将两个库源放在同一个DLL中解决了这个问题。我们的事件库实际上已经定义了用于导出到DLL的宏,并且我们通过组合这两者来消除任何依赖性问题。