我现在正在使用 Boost Unit Test为我的项目执行单元测试。每次运行单元测试时,我都会遇到内存堆栈问题。我调试了BOOST库的源代码,发现问题出在调用unit_test_suite.hpp文件中的以下代码:
void
traverse_test_tree( test_unit_id id, test_tree_visitor& V )
{
global_i = global_i + 1;
std::cout<<global_i<<std::endl;
if( ut_detail::test_id_2_unit_type( id ) == tut_case )
traverse_test_tree( framework::get<test_case>( id ), V );
else
traverse_test_tree( framework::get<test_suite>( id ), V );
}
我从VC10得到的错误信息是:
Unhandled exception at 0x779815de in TestApplication.exe: 0xC00000FD: Stack overflow.
我想知道测试程序有什么问题。谢谢!
编辑 根据建议,我查看了我的代码,然后发生了非常奇怪的事情:如果测试套件与 main() 在同一个程序中定义,它可以工作;但是,如果测试套件来自 .dll,则会发生错误。我列出以下代码来说明我的问题:
boost::unit_test::test_suite* main_global_test_suite;
void Hellotestdll()
{
int i= 1;
int j= 2;
BOOST_CHECK(i == j);
}
boost::unit_test::test_suite* get_abc_test_suite()
{
test_suite* ts = BOOST_TEST_SUITE( "unit_geometric" );
ts->add( BOOST_TEST_CASE( &Hellotestdll ) );
return ts;
}
int main( int argc, char* argv[] )
{
try
{
/**
* Step 1. obtain options
*/
char* optionLine[1024];
int len;
len = obtain_options(optionLine, argc, argv);
/**
* Step 2. perform unit test based on user's options
*/
int test_status=0;
main_global_test_suite = get_abc_test_suite();
test_status = unit_test_main(run_global_test_suite, len, optionLine);
return test_status;
}
catch(std::exception& e)
{
std::cout << e.what() << std::endl;
return 1;
}
catch (const std::string& s)
{
std::cout << s << std::endl;
return 1;
}
catch (...)
{
return 1;
}
}
以上代码运行良好。但是如果测试套件来自 .dll,例如:
// dll_header.h
namespace abc
{
ABC_EXPORT boost::unit_test::test_suite* get_geometric_test_suite();
}
// dll_header.cpp
namespace abc
{
using namespace boost;
using namespace boost::unit_test;
void Hellotestdllabc()
{
int i= 1;
int j= 2;
BOOST_CHECK(i == j);
}
boost::unit_test::test_suite* get_abc_test_suite()
{
test_suite* ts = BOOST_TEST_SUITE( "unit_abc" );
ts->add( BOOST_TEST_CASE( &Hellotestdllabc ) );
return ts;
}
}
然后,如果我使用以下代码调用此测试套件:
int main( int argc, char* argv[] )
{
............
/**
* Step 2. perform unit test based on user's options
*/
int test_status=0;
main_global_test_suite = abc::get_abc_test_suite();
test_status = unit_test_main(run_global_test_suite, len, optionLine);
return test_status;
}
恼人的堆栈溢出错误将会发生。
问题总结
(1) boost dll with MDd (Succeed)
如果我将升压单元测试库(定义为 -DBOOST_ALL_DYN_LINK -DBOOST_TEST_NO_MAIN -DBOOST_TEST_DYN_LINK -DBOOST_ALL_NO_LIB
)和正在运行的可执行程序与相同的动态运行时库(多线程调试 Dll)链接起来(MDd)),它将起作用。
(2) boost dll with MTd (Failed)
如果boost单元测试库(定义为-DBOOST_ALL_DYN_LINK -DBOOST_TEST_NO_MAIN -DBOOST_TEST_DYN_LINK -DBOOST_ALL_NO_LIB
)和正在运行的可执行程序被编译并链接到相同的静态运行时库(多线程) Debu (MTd)),我会崩溃,但是崩溃和我上面报的不一样:
(3) boost static lib with MDd (Failed)
如果 boost 是作为静态库构建的(使用 -DBOOST_TEST_NO_MAIN -DBOOST_ALL_NO_LIB
的定义),并且 boost 库和可执行程序都是使用相同的动态运行时库构建的(医学博士)。将发生以下崩溃:
(4) boost static lib with MTd (Failed)
如果 boost 是作为静态库构建的(使用 -DBOOST_TEST_NO_MAIN -DBOOST_ALL_NO_LIB
的定义),并且 boost 库和可执行程序都是使用相同的静态运行时库构建的(吨)。将发生以下崩溃:
最佳答案
ABC_EXPORT boost::unit_test::test_suite* get_geometric_test_suite();
单元测试的目的是及早发现代码中的问题。那行得通,只是您很早就发现了问题。甚至让单元测试正常运行还为时过早。
返回 C++ 对象指针的 DLL 函数通常是一个问题。只有当 C++ 对象的布局与编译器在编译 DLL 和 EXE 时所做的假设完全匹配时,它才会有好的结果。该对象位于两个模块都可以访问的堆上,这是必需的,因为 DLL 创建该对象并且您的 EXE 需要删除它。
要允许正确删除对象,DLL 和 EXE 必须共享相同的 CRT 版本。当您使用/MT 构建您的程序时,您会遇到麻烦,要求 CRT 的静态版本。相关的编译器设置是C/C++、代码生成、运行时库设置。您的 Debug 配置必须使用/MDd,您的 Release 配置必须使用/MD。对于 EXE 和 DLL 项目,以及编译时的 Boost 库。如果是/MTd 和/MT,则 DLL 将有自己的 CRT 拷贝链接到其中,并将使用自己的堆进行分配。 EXE 无法正确删除该对象,因为它使用了另一个 堆。无论如何这样做都会产生未定义的行为。任何事情都可能发生,只有当您在比 XP 更新的 Windows 版本上运行程序时,您才会走运。当你在附加调试器的情况下运行单元测试时,Vista 和更高版本将使用调试堆,当它注意到传递给::operator delete 的指针无效时,它会调用断点。一定要让链接器自动找到正确的 Boost .lib 链接到,不要自己强制它。
对象布局更可能是您的问题,不幸的是更难诊断。通过使用完全相同的编译器设置构建 EXE 和 DLL,您可以避免麻烦。附加要求是它们必须与用于构建 Boost 库的设置相匹配。这当然是困难的部分,需要时间机器。特别是 _HAS_ITERATOR_DEBUGGING 宏是一个麻烦制造者,像 std::vector 这样的基本 STL 类将有不同的布局,这取决于该宏的值。
我知道这很含糊,但问题中没有足够的信息来真正诊断这个问题。您可以做的一个非常基本的检查是将返回的 boost::unit_test::test_suite 指针放在监视表达式中。如果您在进入 Boost 代码时突然看到该对象的成员发生变化,那么您知道您遇到了对象布局问题。接下来发生的事情是高度不可预测的,堆栈溢出当然是可能的。另一种诊断方法是使用 Debug + Windows + Registers 窗口。跨函数时确保ESP寄存器值稳定。
关于c++ - BOOST单元测试堆栈溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12279198/