c++ - BOOST单元测试堆栈溢出

标签 c++ visual-studio-2010 boost-test

我现在正在使用 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)),我会崩溃,但是崩溃和我上面报的不一样: enter image description here

(3) boost static lib with MDd (Failed)

如果 boost 是作为静态库构建的(使用 -DBOOST_TEST_NO_MAIN -DBOOST_ALL_NO_LIB 的定义),并且 boost 库和可执行程序都是使用相同的动态运行时库构建的(医学博士)。将发生以下崩溃: enter image description here

(4) boost static lib with MTd (Failed)

如果 boost 是作为静态库构建的(使用 -DBOOST_TEST_NO_MAIN -DBOOST_ALL_NO_LIB 的定义),并且 boost 库和可执行程序都是使用相同的静态运行时库构建的(吨)。将发生以下崩溃: enter image description here

最佳答案

   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/

相关文章:

由 小码哥发布于 2019-12-09 17:00:01 c++ #ifdef Mac OS X 问题

c++ - 在写入该变量的唯一线程中使用 memory_order_relaxed 加载原子变量是否安全?

visual-studio-2010 - 如何在 Visual Studio 2012 中设置断点的背景颜色?

visual-studio-2010 - VisualSVN - TortoiseSVN - 自上次提交以来未更改或添加任何文件

c++ - 如何使用 Eclipse 处理 Boost.Test 输出

c++ - Boost 单元测试在 Visual Studio 2012 中抛出异常

c++ - Visual Studio 不断重建和智能感知中断

python - 在 Python 中编译 C 代码的问题

c++ - 运行 boost 测试项目时出错 : testcaseName: No such file or directory

c++ - c++-try block 之后是否需要立即编写catch block ?