将静态库转换为DLL导致main之前的访问冲突
Converting static library to DLL causes access violation before main
我们在 VS2015 中有一个大型解决方案,其中包含两个库和大量 win32 项目,用于测试我们的应用程序。我们的项目及其依赖如下:
事件库
- winmm.dll(用于计时功能)
应用程序库
- eventLibrary.lib(静态)
测试用例
- eventLibrary.lib(静态)
- appLibrary.lib(静态)
- gtestd.lib(静态,Google 测试框架)
这些库最初是静态的,但我们正在将它们转换为 DLL 以加快链接速度。我用 __declspec(dllexport)
装饰器修改了我们的应用程序代码,并成功地将我们的应用程序编译并链接为 DLL。所有不使用 eventLibrary.lib
构建且 运行 成功的测试用例,其余测试用例崩溃,因为 eventLibrary.lib
在 appLibrary.dll
和 testCase.exe
.[=30= 中静态链接]
我将 eventLibrary.lib
转换为一个 DLL,它与我们的 exe 建立并链接,但在它们到达 main
之前就崩溃了。我正在使用 def 文件而不是修改库源。如果我从 testCase.exe
中删除 eventLibrary.dll
依赖项并从 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 测试框架的全局初始化期间,它仍然是一个静态库。调用栈如下:
testCase.exe!testing::Message::operator<<(const char[7] & val) Line 131
testCase.exe!testing::internal::FlagToEnvVar(const char * flag) Line 1136
testCase.exe!testing::internal::BoolFromGTestEnv(const char * flag, bool default_value) Line 1195
testCase.exe!testing::`dynamic initializer for 'FLAGS_gtest_also_run_disabled_tests''() Line 202
动态链接我们的事件库是否以某种方式破坏了 testCase.exe
中的内存?这与拥有自己的堆的 DLL 有什么关系吗?我确保我们的 DLL 和 exe 在构建和链接时使用相同的运行时 (/MDd
) 和相同的标志进行编译。
我通过将两个库源放在同一个 DLL 中解决了这个问题。我们的事件库实际上定义了用于导出到 DLL 的宏,并且我们通过将两者结合起来消除了任何依赖性问题。
我们在 VS2015 中有一个大型解决方案,其中包含两个库和大量 win32 项目,用于测试我们的应用程序。我们的项目及其依赖如下:
事件库
- winmm.dll(用于计时功能)
应用程序库
- eventLibrary.lib(静态)
测试用例
- eventLibrary.lib(静态)
- appLibrary.lib(静态)
- gtestd.lib(静态,Google 测试框架)
这些库最初是静态的,但我们正在将它们转换为 DLL 以加快链接速度。我用 __declspec(dllexport)
装饰器修改了我们的应用程序代码,并成功地将我们的应用程序编译并链接为 DLL。所有不使用 eventLibrary.lib
构建且 运行 成功的测试用例,其余测试用例崩溃,因为 eventLibrary.lib
在 appLibrary.dll
和 testCase.exe
.[=30= 中静态链接]
我将 eventLibrary.lib
转换为一个 DLL,它与我们的 exe 建立并链接,但在它们到达 main
之前就崩溃了。我正在使用 def 文件而不是修改库源。如果我从 testCase.exe
中删除 eventLibrary.dll
依赖项并从 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 测试框架的全局初始化期间,它仍然是一个静态库。调用栈如下:
testCase.exe!testing::Message::operator<<(const char[7] & val) Line 131 testCase.exe!testing::internal::FlagToEnvVar(const char * flag) Line 1136 testCase.exe!testing::internal::BoolFromGTestEnv(const char * flag, bool default_value) Line 1195 testCase.exe!testing::`dynamic initializer for 'FLAGS_gtest_also_run_disabled_tests''() Line 202
动态链接我们的事件库是否以某种方式破坏了 testCase.exe
中的内存?这与拥有自己的堆的 DLL 有什么关系吗?我确保我们的 DLL 和 exe 在构建和链接时使用相同的运行时 (/MDd
) 和相同的标志进行编译。
我通过将两个库源放在同一个 DLL 中解决了这个问题。我们的事件库实际上定义了用于导出到 DLL 的宏,并且我们通过将两者结合起来消除了任何依赖性问题。