2011-05-23 48 views
4

我正在爲一個神祕問題而努力 我只能在RHEL4發行版上看到。我的一些單元測試(使用boost 1.36單元測試框架)在RHEL4(gcc 3.4.6)上失敗並且使用發佈構建類型。我沒有看到使用RHEL5版本或調試版本類型(gcc 4.1.2,boost-1.39)的問題;我也不會使用Visual Studio 2005(使用boost-1.36)或2008(使用boost-1.39)在Windows 32位或64位上看到它。RHEL4發行版使用boost 1.36和C++發行版

懷疑這可能是由於一些微妙的內存問題,我繼續在測試應用程序上運行valgrind(保留問題的最小案例)。以下是我的valgrind使用「滿,沒有到達」模式得到了,當我跑:

==12285== Memcheck, a memory error detector. 
==12285== Copyright (C) 2002-2005, and GNU GPL'd, by Julian Seward et al. 
==12285== Using LibVEX rev 1575, a library for dynamic binary translation. 
==12285== Copyright (C) 2004-2005, and GNU GPL'd, by OpenWorks LLP. 
==12285== Using valgrind-3.1.1, a dynamic binary instrumentation framework. 
==12285== Copyright (C) 2000-2005, and GNU GPL'd, by Julian Seward et al. 
==12285== For more details, rerun with: -v 
==12285== 
==12285== My PID = 12285, parent PID = 12284. Prog and args are: 
==12285== ./myprojd 
==12285== 
==12285== Syscall param sigaltstack(ss) points to uninitialised byte(s) 
==12285== at 0x3AD682EDA9: sigaltstack (in /lib64/tls/libc-2.3.4.so) 
==12285== by 0x6488638: boost::detail::signal_handler::~signal_handler() 
      (in /<path_to>/libboost_unit_test_framework-gcc34-mt-1_36.so.1.36.0) 
==12285== by 0x648975E: boost::execution_monitor::catch_signals 
      (boost::unit_test::callback0<int> const&) 
      (in /<path_to>/libboost_unit_test_framework-gcc34-mt-1_36.so.1.36.0) 
==12285== by 0x6489813: boost::execution_monitor::execute 
      (boost::unit_test::callback0<int> const&) 
      (in /<path_to>/libboost_unit_test_framework-gcc34-mt-1_36.so.1.36.0) 
==12285== by 0x648F2E4: boost::unit_test::framework::run(unsigned long, bool) 
      (in /<path_to>/libboost_unit_test_framework-gcc34-mt-1_36.so.1.36.0) 
==12285== by 0x649BD02: boost::unit_test::unit_test_main(bool (*)(), int, char**) 
      (in /<path_to>/libboost_unit_test_framework-gcc34-mt-1_36.so.1.36.0) 
==12285== by 0x4147F0: main (init.cpp:132) 
==12285== Address 0x7FEFFF3B0 is on thread 1's stack 
==12285== 
==12285== ERROR SUMMARY: 6 errors from 1 contexts (suppressed: 4 from 1) 
==12285== malloc/free: in use at exit: 190,112 bytes in 1,869 blocks. 
==12285== malloc/free: 23,128 allocs, 21,259 frees, 2,520,845 bytes allocated. 
==12285== For counts of detected errors, rerun with: -v 
==12285== searching for pointers to 1,869 not-freed blocks. 
==12285== checked 2,184,272 bytes. 
==12285== 
==12285== LEAK SUMMARY: 
==12285== definitely lost: 0 bytes in 0 blocks. 
==12285==  possibly lost: 0 bytes in 0 blocks. 
==12285== still reachable: 190,112 bytes in 1,869 blocks. 
==12285==   suppressed: 0 bytes in 0 blocks. 
==12285== Reachable blocks (those to which a pointer was found) are not shown. 
==12285== To see them, rerun with: --show-reachable=yes 

Ofcourse,我在調試模式下運行這個(但我說過在釋放模式只發生了錯誤)。如果我在釋放模式下運行valgrind,我會得到相同的輸出(也許 較少的細節,如行號)。從這看來,這個問題似乎在boost-1.36,或者我的init_unit_test_suite的定義?顯然,我可以嘗試的一件事是在所有平臺上使用boost-1.39運行 ;但不幸的是,我們目前在RHEL4和VS2005上使用boost-1.36,所以這可能不實用。

我還觀察到,在測試失敗的地方強制某個記錄器輸出到控制檯,使測試通過(我知道不好)!懷疑這可能是因爲我評論了所有記錄器輸出並運行valgrind - 所以這就是上面的內容。如果你需要一些init_unit_test_suite函數的代碼片段;如果有幫助,我可以發佈。任何想法來解決這個問題都是受歡迎的並且非常感謝

05月26日編輯:

這裏的init_unit_test_suite - 感激,如果有人能看一看。

std::ofstream log_stream; 
std::ofstream report_stream; 

const_string retrieve_framework_parameter(const_string cla_name, int argc, char** argv) { 
    //- first try to find parameter among command line arguments if present 
    if(argc) { 
     //- locate corresponding cla name 
     if(!cla_name.is_empty()) { 
      for(int i = 1; i < argc; ++i) { 
       if(cla_name == const_string(argv[i], cla_name.size()) && argv[i][cla_name.size()] == '=') { 
        const_string result = argv[i] + cla_name.size() + 1; 

        for(int j = i; j < argc; ++j) { 
         argv[j] = argv[j+1]; 
        } 
        --argc; 

        return result; 
       } 
      } 
     } 
    } 
    return std::getenv(cla_name.begin()); 
} 
//! Format results to CPP UNIT xml 
class simple_report_formatter : public results_reporter::format { 

public: 
    virtual void results_report_start(std::ostream&) { 
    } 
    virtual void results_report_finish(std::ostream&) { 
    } 
    virtual void test_unit_report_start(test_unit const&, std::ostream&) { 
    } 
    virtual void test_unit_report_finish(test_unit const& tu, std::ostream& out) { 
     if(tu.p_type == tut_case) { 
      const test_results& r = results_collector.results(tu.p_id); 
      if(r.passed()) { 
       out<<"[PASS] "; 
      } else { 
       out<<"[FAIL] "; 
      } 
      out<<"Test Case <unit_"<<tu.p_name.get()<<"> "; 
      if(!r.passed()) { 
       out<<" - "; 
       out<<"!! Assertions failed: "<<r.p_assertions_failed; 
       out<<" - See log files for details on failures !!"; 
      } 
      out<<std::endl; 

#if defined(MYPROJ_WINDOWS) && defined(MYPROJ_DEBUG) 
      if(!r.passed()) { 
       std::ostringstream msg; 
       msg<<"!! "<<tu.p_name.get()<<" FAILED !!"<<std::endl; 
       OutputDebugStringA(msg.str().c_str()); 
      } 
#endif 
     } 
    } 
    virtual void do_confirmation_report(test_unit const&, std::ostream&) { 
    } 
}; 


bool init_unit_test_suite() { 
const_string log_file = retrieve_framework_parameter(
    "--log_file", 
    framework::master_test_suite().argc, 
    framework::master_test_suite().argv 
); 
if(!log_file.empty()) { 
    log_stream.open(log_file.begin()); 
    unit_test_log.set_stream(log_stream); 
} 

const_string report_file = retrieve_framework_parameter(
    "--report_file", 
    framework::master_test_suite().argc, 
    framework::master_test_suite().argv 
); 
if(!report_file.empty()) { 
    report_stream.open(report_file.begin()); 
    results_reporter::set_stream(report_stream); 
} 
if(runtime_config::report_format() == CLF) { 
    results_reporter::set_format(new simple_report_formatter); 
} 

// This is providing the sensible default configuration when the test is being run 
// without any input parameters whatsoever: print the final report to console 
if(framework::master_test_suite().argc <= 1) {   
    results_reporter::set_stream(std::cout); 
    results_reporter::set_format(new simple_report_formatter); 
    results_reporter::set_level(DETAILED_REPORT); 
} 

framework::master_test_suite().p_name.set(MYPROJ_TEST_SUITE_NAME); 
return true; 
} 
+1

我忽略了它可能是一個積極的編譯器優化設置的可能性。會試試這個。還將發佈init_unit_test_suite(..)函數明天。謝謝。 – 2011-05-25 04:43:07

回答

1

valgrind中的這個「錯誤」不一定是個問題。當在Linux中調用系統調用時,內存通常必須從用戶空間複製到內核空間。在這樣做時,它可能會複製未初始化的字節。

僅僅因爲它將這些字節複製到內核空間並不意味着內核實際上會對未初始化的字節做任何事情。內核對字節的處理在很大程度上取決於所討論的系統調用的語義。

Valgrind沒有簡單的方法知道系統調用中傳遞的某些字節是否未初始化,因此它總是表示錯誤。許多類似的錯誤被valgrind壓制。

你可以看到一些Valgrind的默認鎮壓在這個文件:/usr/lib/valgrind/default.supp您也可以創建自己的文件抑制,如果你喜歡,並利用它們在你的單元測試取消錯誤信息。如果您在此係統上沒有遇到任何實際問題,那麼抑制錯誤可能是一個好主意。請參閱valgrind的命令行選項。

+0

謝謝@jcoffland!雖然您的回覆無法解決問題,但我感謝您花時間閱讀並提供了您的見解。 – 2011-07-14 01:32:14

+0

沒有任何反對@jcoffland,但不應該這個答案被投票而不是接受?被接受的事實意味着問題被認爲解決了,但事實並非如此。我正在投票答案,以使我的評論業力中立。 :) – 2012-03-20 23:54:17