| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565 |
- /*=========================================================================
- Program: CMake - Cross-Platform Makefile Generator
- Module: $RCSfile$
- Language: C++
- Date: $Date$
- Version: $Revision$
- Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
- See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
- This software is distributed WITHOUT ANY WARRANTY; without even
- the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- PURPOSE. See the above copyright notices for more information.
- =========================================================================*/
- #include "cmCTestMemCheckHandler.h"
- #include "cmCTest.h"
- #include "cmake.h"
- #include "cmGeneratedFileStream.h"
- #include <cmsys/Process.h>
- #include <cmsys/RegularExpression.hxx>
- #include <cmsys/Base64.h>
- #include "cmMakefile.h"
- #include <stdlib.h>
- #include <math.h>
- #include <float.h>
- //----------------------------------------------------------------------
- static const char* cmCTestMemCheckResultStrings[] = {
- "ABR",
- "ABW",
- "ABWL",
- "COR",
- "EXU",
- "FFM",
- "FIM",
- "FMM",
- "FMR",
- "FMW",
- "FUM",
- "IPR",
- "IPW",
- "MAF",
- "MLK",
- "MPK",
- "NPR",
- "ODS",
- "PAR",
- "PLK",
- "UMC",
- "UMR",
- 0
- };
- //----------------------------------------------------------------------
- static const char* cmCTestMemCheckResultLongStrings[] = {
- "Threading Problem",
- "ABW",
- "ABWL",
- "COR",
- "EXU",
- "FFM",
- "FIM",
- "Mismatched deallocation",
- "FMR",
- "FMW",
- "FUM",
- "IPR",
- "IPW",
- "MAF",
- "Memory Leak",
- "Potential Memory Leak",
- "NPR",
- "ODS",
- "Invalid syscall param",
- "PLK",
- "Uninitialized Memory Conditional",
- "Uninitialized Memory Read",
- 0
- };
- //----------------------------------------------------------------------
- cmCTestMemCheckHandler::cmCTestMemCheckHandler()
- {
- m_MemCheck = true;
- }
- //----------------------------------------------------------------------
- void cmCTestMemCheckHandler::Initialize()
- {
- this->Superclass::Initialize();
- m_MemoryTester = "";
- m_MemoryTesterOptionsParsed.clear();
- m_MemoryTesterOptions = "";
- m_MemoryTesterStyle = UNKNOWN;
- m_MemoryTesterOutputFile = "";
- int cc;
- for ( cc = 0; cc < NO_MEMORY_FAULT; cc ++ )
- {
- m_MemoryTesterGlobalResults[cc] = 0;
- }
- }
- //----------------------------------------------------------------------
- int cmCTestMemCheckHandler::PreProcessHandler()
- {
- if ( !this->InitializeMemoryChecking() )
- {
- return 0;
- }
- if ( !this->ExecuteCommands(m_CustomPreMemCheck) )
- {
- cmCTestLog(m_CTest, ERROR_MESSAGE, "Problem executing pre-memcheck command(s)." << std::endl);
- return 0;
- }
- return 1;
- }
- //----------------------------------------------------------------------
- int cmCTestMemCheckHandler::PostProcessHandler()
- {
- if ( !this->ExecuteCommands(m_CustomPostMemCheck) )
- {
- cmCTestLog(m_CTest, ERROR_MESSAGE, "Problem executing post-memcheck command(s)." << std::endl);
- return 0;
- }
- return 1;
- }
- //----------------------------------------------------------------------
- void cmCTestMemCheckHandler::GenerateTestCommand(std::vector<const char*>& args)
- {
- std::vector<cmStdString>::size_type pp;
- args.push_back(m_MemoryTester.c_str());
- std::string memcheckcommand = "";
- memcheckcommand = m_MemoryTester;
- for ( pp = 0; pp < m_MemoryTesterOptionsParsed.size(); pp ++ )
- {
- args.push_back(m_MemoryTesterOptionsParsed[pp].c_str());
- memcheckcommand += " ";
- memcheckcommand += cmSystemTools::EscapeSpaces(m_MemoryTesterOptionsParsed[pp].c_str());
- }
- cmCTestLog(m_CTest, HANDLER_VERBOSE_OUTPUT, "Memory check command: " << memcheckcommand << std::endl);
- }
- //----------------------------------------------------------------------
- void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile *mf)
- {
- this->cmCTestTestHandler::PopulateCustomVectors(mf);
- cmCTest::PopulateCustomVector(mf, "CTEST_CUSTOM_PRE_MEMCHECK",
- m_CustomPreMemCheck);
- cmCTest::PopulateCustomVector(mf, "CTEST_CUSTOM_POST_MEMCHECK",
- m_CustomPostMemCheck);
- cmCTest::PopulateCustomVector(mf,
- "CTEST_CUSTOM_MEMCHECK_IGNORE",
- m_CustomTestsIgnore);
- }
- //----------------------------------------------------------------------
- void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
- {
- if ( !m_CTest->GetProduceXML() )
- {
- return;
- }
- m_CTest->StartXML(os);
- os << "<DynamicAnalysis Checker=\"";
- switch ( m_MemoryTesterStyle )
- {
- case cmCTestMemCheckHandler::VALGRIND:
- os << "Valgrind";
- break;
- case cmCTestMemCheckHandler::PURIFY:
- os << "Purify";
- break;
- case cmCTestMemCheckHandler::BOUNDS_CHECKER:
- os << "BoundsChecker";
- break;
- default:
- os << "Unknown";
- }
- os << "\">" << std::endl;
- os << "\t<StartDateTime>" << m_StartTest << "</StartDateTime>\n"
- << "\t<TestList>\n";
- tm_TestResultsVector::size_type cc;
- for ( cc = 0; cc < m_TestResults.size(); cc ++ )
- {
- cmCTestTestResult *result = &m_TestResults[cc];
- std::string testPath = result->m_Path + "/" + result->m_Name;
- os << "\t\t<Test>" << cmCTest::MakeXMLSafe(
- m_CTest->GetShortPathToFile(testPath.c_str()))
- << "</Test>" << std::endl;
- }
- os << "\t</TestList>\n";
- cmCTestLog(m_CTest, HANDLER_OUTPUT, "-- Processing memory checking output: ");
- unsigned int total = m_TestResults.size();
- unsigned int step = total / 10;
- unsigned int current = 0;
- for ( cc = 0; cc < m_TestResults.size(); cc ++ )
- {
- cmCTestTestResult *result = &m_TestResults[cc];
- std::string memcheckstr;
- int memcheckresults[cmCTestMemCheckHandler::NO_MEMORY_FAULT];
- int kk;
- bool res = this->ProcessMemCheckOutput(result->m_Output, memcheckstr, memcheckresults);
- if ( res && result->m_Status == cmCTestMemCheckHandler::COMPLETED )
- {
- continue;
- }
- os << "\t<Test Status=\"";
- if ( result->m_Status == cmCTestMemCheckHandler::COMPLETED )
- {
- os << "passed";
- }
- else if ( result->m_Status == cmCTestMemCheckHandler::NOT_RUN )
- {
- os << "notrun";
- }
- else
- {
- os << "failed";
- }
- std::string testPath = result->m_Path + "/" + result->m_Name;
- os << "\">\n"
- << "\t\t<Name>" << cmCTest::MakeXMLSafe(result->m_Name) << "</Name>\n"
- << "\t\t<Path>" << cmCTest::MakeXMLSafe(
- m_CTest->GetShortPathToFile(result->m_Path.c_str())) << "</Path>\n"
- << "\t\t<FullName>" << cmCTest::MakeXMLSafe(
- m_CTest->GetShortPathToFile(testPath.c_str())) << "</FullName>\n"
- << "\t\t<FullCommandLine>"
- << cmCTest::MakeXMLSafe(result->m_FullCommandLine)
- << "</FullCommandLine>\n"
- << "\t\t<Results>" << std::endl;
- for ( kk = 0; cmCTestMemCheckResultLongStrings[kk]; kk ++ )
- {
- if ( memcheckresults[kk] )
- {
- os << "\t\t\t<Defect type=\"" << cmCTestMemCheckResultLongStrings[kk] << "\">"
- << memcheckresults[kk]
- << "</Defect>" << std::endl;
- }
- m_MemoryTesterGlobalResults[kk] += memcheckresults[kk];
- }
- os
- << "\t\t</Results>\n"
- << "\t<Log>\n" << memcheckstr << std::endl
- << "\t</Log>\n"
- << "\t</Test>" << std::endl;
- if ( current < cc )
- {
- cmCTestLog(m_CTest, HANDLER_OUTPUT, "#" << std::flush);
- current += step;
- }
- }
- cmCTestLog(m_CTest, HANDLER_OUTPUT, std::endl);
- cmCTestLog(m_CTest, HANDLER_OUTPUT, "Memory checking results:" << std::endl);
- os << "\t<DefectList>" << std::endl;
- for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
- {
- if ( m_MemoryTesterGlobalResults[cc] )
- {
- #ifdef cerr
- # undef cerr
- #endif
- std::cerr.width(35);
- #define cerr no_cerr
- cmCTestLog(m_CTest, HANDLER_OUTPUT, cmCTestMemCheckResultLongStrings[cc] << " - "
- << m_MemoryTesterGlobalResults[cc] << std::endl);
- os << "\t\t<Defect Type=\"" << cmCTestMemCheckResultLongStrings[cc] << "\"/>" << std::endl;
- }
- }
- os << "\t</DefectList>" << std::endl;
- os << "\t<EndDateTime>" << m_EndTest << "</EndDateTime>" << std::endl;
- os << "<ElapsedMinutes>"
- << static_cast<int>(m_ElapsedTestingTime/6)/10.0
- << "</ElapsedMinutes>\n";
-
- os << "</DynamicAnalysis>" << std::endl;
- m_CTest->EndXML(os);
- }
- //----------------------------------------------------------------------
- bool cmCTestMemCheckHandler::InitializeMemoryChecking()
- {
- // Setup the command
- if ( cmSystemTools::FileExists(m_CTest->GetCTestConfiguration("MemoryCheckCommand").c_str()) )
- {
- m_MemoryTester
- = cmSystemTools::ConvertToOutputPath(m_CTest->GetCTestConfiguration("MemoryCheckCommand").c_str());
- }
- else if ( cmSystemTools::FileExists(m_CTest->GetCTestConfiguration("PurifyCommand").c_str()) )
- {
- m_MemoryTester
- = cmSystemTools::ConvertToOutputPath(m_CTest->GetCTestConfiguration("PurifyCommand").c_str());
- }
- else if ( cmSystemTools::FileExists(m_CTest->GetCTestConfiguration("ValgrindCommand").c_str()) )
- {
- m_MemoryTester
- = cmSystemTools::ConvertToOutputPath(m_CTest->GetCTestConfiguration("ValgrindCommand").c_str());
- }
- else
- {
- cmCTestLog(m_CTest, ERROR_MESSAGE, "Memory checker (MemoryCheckCommand) not set, or cannot find the specified program."
- << std::endl);
- return false;
- }
- if ( m_MemoryTester[0] == '\"' && m_MemoryTester[m_MemoryTester.size()-1] == '\"' )
- {
- m_MemoryTester = m_MemoryTester.substr(1, m_MemoryTester.size()-2);
- }
- // Setup the options
- if ( m_CTest->GetCTestConfiguration("MemoryCheckCommandOptions").size() )
- {
- m_MemoryTesterOptions = m_CTest->GetCTestConfiguration("MemoryCheckCommandOptions");
- }
- else if ( m_CTest->GetCTestConfiguration("ValgrindCommandOptions").size() )
- {
- m_MemoryTesterOptions = m_CTest->GetCTestConfiguration("ValgrindCommandOptions");
- }
- m_MemoryTesterOutputFile = m_CTest->GetBinaryDir() + "/Testing/Temporary/MemoryChecker.log";
- m_MemoryTesterOutputFile = cmSystemTools::EscapeSpaces(m_MemoryTesterOutputFile.c_str());
- if ( m_MemoryTester.find("valgrind") != std::string::npos )
- {
- m_MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
- if ( !m_MemoryTesterOptions.size() )
- {
- m_MemoryTesterOptions = "-q --tool=memcheck --leak-check=yes --show-reachable=yes --workaround-gcc296-bugs=yes --num-callers=100";
- }
- if ( m_CTest->GetCTestConfiguration("MemoryCheckSuppressionFile").size() )
- {
- if ( !cmSystemTools::FileExists(m_CTest->GetCTestConfiguration("MemoryCheckSuppressionFile").c_str()) )
- {
- cmCTestLog(m_CTest, ERROR_MESSAGE, "Cannot find memory checker suppression file: "
- << m_CTest->GetCTestConfiguration("MemoryCheckSuppressionFile").c_str() << std::endl);
- return false;
- }
- m_MemoryTesterOptions += " --suppressions=" + cmSystemTools::EscapeSpaces(m_CTest->GetCTestConfiguration("MemoryCheckSuppressionFile").c_str()) + "";
- }
- }
- else if ( m_MemoryTester.find("purify") != std::string::npos )
- {
- m_MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
- #ifdef _WIN32
- m_MemoryTesterOptions += " /SAVETEXTDATA=" + m_MemoryTesterOutputFile;
- #else
- m_MemoryTesterOptions += " -log-file=" + m_MemoryTesterOutputFile;
- #endif
- }
- else if ( m_MemoryTester.find("boundschecker") != std::string::npos )
- {
- m_MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
- cmCTestLog(m_CTest, ERROR_MESSAGE, "Bounds checker not yet implemented" << std::endl);
- return false;
- }
- else
- {
- cmCTestLog(m_CTest, ERROR_MESSAGE, "Do not understand memory checker: " << m_MemoryTester.c_str() << std::endl);
- return false;
- }
- m_MemoryTesterOptionsParsed = cmSystemTools::ParseArguments(m_MemoryTesterOptions.c_str());
- std::vector<cmStdString>::size_type cc;
- for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
- {
- m_MemoryTesterGlobalResults[cc] = 0;
- }
- return true;
- }
- //----------------------------------------------------------------------
- bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str,
- std::string& log, int* results)
- {
- std::string::size_type cc;
- for ( cc = 0; cc < cmCTestMemCheckHandler::NO_MEMORY_FAULT; cc ++ )
- {
- results[cc] = 0;
- }
- if ( m_MemoryTesterStyle == cmCTestMemCheckHandler::VALGRIND )
- {
- return this->ProcessMemCheckValgrindOutput(str, log, results);
- }
- else if ( m_MemoryTesterStyle == cmCTestMemCheckHandler::PURIFY )
- {
- return this->ProcessMemCheckPurifyOutput(str, log, results);
- }
- else if ( m_MemoryTesterStyle == cmCTestMemCheckHandler::BOUNDS_CHECKER )
- {
- log.append("\nMemory checking style used was: ");
- log.append("Bounds Checker");
- }
- else
- {
- log.append("\nMemory checking style used was: ");
- log.append("None that I know");
- log = str;
- }
- return true;
- }
- //----------------------------------------------------------------------
- bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
- const std::string&, std::string& log,
- int* results)
- {
- if ( !cmSystemTools::FileExists(m_MemoryTesterOutputFile.c_str()) )
- {
- log = "Cannot find Purify output file: " + m_MemoryTesterOutputFile;
- cmCTestLog(m_CTest, ERROR_MESSAGE, log.c_str() << std::endl);
- return false;
- }
- std::ifstream ifs(m_MemoryTesterOutputFile.c_str());
- if ( !ifs )
- {
- log = "Cannot read Purify output file: " + m_MemoryTesterOutputFile;
- cmCTestLog(m_CTest, ERROR_MESSAGE, log.c_str() << std::endl);
- return false;
- }
- cmOStringStream ostr;
- log = "";
- cmsys::RegularExpression pfW("^\\[[WEI]\\] ([A-Z][A-Z][A-Z][A-Z]*): ");
- int defects = 0;
- std::string line;
- while ( cmSystemTools::GetLineFromStream(ifs, line) )
- {
- int failure = cmCTestMemCheckHandler::NO_MEMORY_FAULT;
- if ( pfW.find(line) )
- {
- int cc;
- for ( cc = 0; cc < cmCTestMemCheckHandler::NO_MEMORY_FAULT; cc ++ )
- {
- if ( pfW.match(1) == cmCTestMemCheckResultStrings[cc] )
- {
- failure = cc;
- break;
- }
- }
- if ( cc == cmCTestMemCheckHandler::NO_MEMORY_FAULT )
- {
- cmCTestLog(m_CTest, ERROR_MESSAGE, "Unknown Purify memory fault: " << pfW.match(1) << std::endl);
- ostr << "*** Unknown Purify memory fault: " << pfW.match(1) << std::endl;
- }
- }
- if ( failure != NO_MEMORY_FAULT )
- {
- ostr << "<b>" << cmCTestMemCheckResultStrings[failure] << "</b> ";
- results[failure] ++;
- defects ++;
- }
- ostr << cmCTest::MakeXMLSafe(line) << std::endl;
- }
- log = ostr.str();
- if ( defects )
- {
- return false;
- }
- return true;
- }
- //----------------------------------------------------------------------
- bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
- const std::string& str, std::string& log,
- int* results)
- {
- std::vector<cmStdString> lines;
- cmSystemTools::Split(str.c_str(), lines);
-
- std::string::size_type cc;
- cmOStringStream ostr;
- log = "";
- int defects = 0;
- cmsys::RegularExpression valgrindLine("^==[0-9][0-9]*==");
- cmsys::RegularExpression vgFIM(
- "== .*Invalid free\\(\\) / delete / delete\\[\\]");
- cmsys::RegularExpression vgFMM(
- "== .*Mismatched free\\(\\) / delete / delete \\[\\]");
- cmsys::RegularExpression vgMLK(
- "== .*[0-9][0-9]* bytes in [0-9][0-9]* blocks are definitely lost"
- " in loss record [0-9][0-9]* of [0-9]");
- cmsys::RegularExpression vgPAR(
- "== .*Syscall param .* contains unaddressable byte\\(s\\)");
- cmsys::RegularExpression vgMPK1(
- "== .*[0-9][0-9]* bytes in [0-9][0-9]* blocks are possibly lost in"
- " loss record [0-9][0-9]* of [0-9]");
- cmsys::RegularExpression vgMPK2(
- "== .*[0-9][0-9]* bytes in [0-9][0-9]* blocks are still reachable"
- " in loss record [0-9][0-9]* of [0-9]");
- cmsys::RegularExpression vgUMC(
- "== .*Conditional jump or move depends on uninitialised value\\(s\\)");
- cmsys::RegularExpression vgUMR1("== .*Use of uninitialised value of size [0-9][0-9]*");
- cmsys::RegularExpression vgUMR2("== .*Invalid read of size [0-9][0-9]*");
- cmsys::RegularExpression vgUMR3("== .*Jump to the invalid address ");
- cmsys::RegularExpression vgUMR4(
- "== .*Syscall param .* contains uninitialised or unaddressable byte\\(s\\)");
- cmsys::RegularExpression vgIPW("== .*Invalid write of size [0-9]");
- cmsys::RegularExpression vgABR("== .*pthread_mutex_unlock: mutex is locked by a different thread");
- double sttime = cmSystemTools::GetTime();
- cmCTestLog(m_CTest, DEBUG, "Start test: " << lines.size() << std::endl);
- for ( cc = 0; cc < lines.size(); cc ++ )
- {
- if ( valgrindLine.find(lines[cc]) )
- {
- int failure = cmCTestMemCheckHandler::NO_MEMORY_FAULT;
- if ( vgFIM.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::FIM; }
- else if ( vgFMM.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::FMM; }
- else if ( vgMLK.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::MLK; }
- else if ( vgPAR.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::PAR; }
- else if ( vgMPK1.find(lines[cc]) ){ failure = cmCTestMemCheckHandler::MPK; }
- else if ( vgMPK2.find(lines[cc]) ){ failure = cmCTestMemCheckHandler::MPK; }
- else if ( vgUMC.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::UMC; }
- else if ( vgUMR1.find(lines[cc]) ){ failure = cmCTestMemCheckHandler::UMR; }
- else if ( vgUMR2.find(lines[cc]) ){ failure = cmCTestMemCheckHandler::UMR; }
- else if ( vgUMR3.find(lines[cc]) ){ failure = cmCTestMemCheckHandler::UMR; }
- else if ( vgUMR4.find(lines[cc]) ){ failure = cmCTestMemCheckHandler::UMR; }
- else if ( vgIPW.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::IPW; }
- else if ( vgABR.find(lines[cc]) ) { failure = cmCTestMemCheckHandler::ABR; }
- if ( failure != cmCTestMemCheckHandler::NO_MEMORY_FAULT )
- {
- ostr << "<b>" << cmCTestMemCheckResultStrings[failure] << "</b> ";
- results[failure] ++;
- defects ++;
- }
- ostr << cmCTest::MakeXMLSafe(lines[cc]) << std::endl;
- }
- }
- cmCTestLog(m_CTest, DEBUG, "End test (elapsed: " << (cmSystemTools::GetTime() - sttime) << std::endl);
- log = ostr.str();
- if ( defects )
- {
- return false;
- }
- return true;
- }
|