سؤال

I am struggling with a mysterious problem I only see on my RHEL4 release build. Some of my unit tests (using boost 1.36 unit test framework) fail on RHEL4 (gcc 3.4.6) and using release build-type. I do not see the problem using RHEL5 release or debug build types (gcc 4.1.2, boost-1.39); neither do I see it on Windows 32 bit or 64 bit using either Visual Studio 2005 (using boost-1.36) or 2008 (using boost-1.39).

Suspecting that this may be due to some subtle memory issue, I proceeded to run valgrind on the test application (minimal case that preserved the problem). Here is what I got when I ran valgrind using "full, no-reachable" mode:

==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, I ran this in debug mode (although as I mentioned the error occurs only in release mode). If I run valgrind in release mode, I get the same output (with perhaps less detail such as line #s). From this it appears that the problem is somehow in boost-1.36, or perhaps my definition of init_unit_test_suite? Clearly one thing I can try is to run using boost-1.39 on all platforms; but unfortunately, we're currently on boost-1.36 for RHEL4 and VS2005, and so this may not be practical yet.

I also observe that forcing a certain logger output to console at a point where the test fails, enables the test to pass (not good, I know)! Suspecting that this might be due that I commented all logger output and ran valgrind - so that's what's posted above. If you need some code snippets of the init_unit_test_suite function; I can post that, if it helps. Any ideas to resolve this are welcome and greatly appreciated.

05/26/2011 Edit:

Here's the init_unit_test_suite - appreciate if somebody could take a look.

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;
}
هل كانت مفيدة؟

المحلول

This "error" in valgrind is not necessarily a problem. When a system call is called in Linux the memory often has to be copied from users space to kernel space. In doing so the it may copy uninitialized bytes.

Just because it copies these bytes into kernel space does not mean the kernel will actually do anything with the uninitialized bytes. What the kernel does with the bytes depends heavily on the semantics of the system call in question.

Valgrind has no simple way of knowing if it is OK that some of the bytes passed in the system call are uninitialized so it always signals an error. Many of similar errors are suppressed by valgrind.

You can see some of valgrind's default suppressions in this file: /usr/lib/valgrind/default.supp You can also create your own suppression files if you like and use them in your unit test to suppress the error message. If you are not experiencing any actual problems on this system them suppressing the error is probably a good idea. See valgrind's command line options.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top