ctest_memcheck: Add support for ThreadSanitizer
This commit adds support for ThreadSanitizer to ctest. ThreadSanitizer is part of the clang compiler and also gcc 4.8 and later. You have to compile the code with special flags. Then your code gets the the ThreadSanitizer ability built into it. To pass options to the ThreadSanitizer you use an environment variable. This commit teaches ctest to parse the output from ThreadSanitizer and send it to CDash.
This commit is contained in:
parent
4e7983bc06
commit
49948f7221
|
@ -344,6 +344,7 @@ Variables for CTest
|
||||||
/variable/CTEST_MEMORYCHECK_COMMAND
|
/variable/CTEST_MEMORYCHECK_COMMAND
|
||||||
/variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS
|
/variable/CTEST_MEMORYCHECK_COMMAND_OPTIONS
|
||||||
/variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE
|
/variable/CTEST_MEMORYCHECK_SUPPRESSIONS_FILE
|
||||||
|
/variable/CTEST_MEMORYCHECK_TYPE
|
||||||
/variable/CTEST_NIGHTLY_START_TIME
|
/variable/CTEST_NIGHTLY_START_TIME
|
||||||
/variable/CTEST_P4_CLIENT
|
/variable/CTEST_P4_CLIENT
|
||||||
/variable/CTEST_P4_COMMAND
|
/variable/CTEST_P4_COMMAND
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
CTEST_MEMORYCHECK_TYPE
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Specify the CTest ``MemoryCheckType`` setting
|
||||||
|
in a :manual:`ctest(1)` dashboard client script.
|
||||||
|
Valid values are Valgrind, Purify, BoundsChecker, and ThreadSanitizer.
|
|
@ -20,6 +20,8 @@ cmCTestGenericHandler* cmCTestMemCheckCommand::InitializeActualHandler()
|
||||||
cmCTestGenericHandler* handler
|
cmCTestGenericHandler* handler
|
||||||
= this->CTest->GetInitializedHandler("memcheck");
|
= this->CTest->GetInitializedHandler("memcheck");
|
||||||
|
|
||||||
|
this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
|
||||||
|
"MemoryCheckType", "CTEST_MEMORYCHECK_TYPE");
|
||||||
this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
|
this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
|
||||||
"MemoryCheckCommand", "CTEST_MEMORYCHECK_COMMAND");
|
"MemoryCheckCommand", "CTEST_MEMORYCHECK_COMMAND");
|
||||||
this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
|
this->CTest->SetCTestConfigurationFromCMakeVariable(this->Makefile,
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <cmsys/Process.h>
|
#include <cmsys/Process.h>
|
||||||
#include <cmsys/RegularExpression.hxx>
|
#include <cmsys/RegularExpression.hxx>
|
||||||
#include <cmsys/Base64.h>
|
#include <cmsys/Base64.h>
|
||||||
|
#include <cmsys/Glob.hxx>
|
||||||
#include <cmsys/FStream.hxx>
|
#include <cmsys/FStream.hxx>
|
||||||
#include "cmMakefile.h"
|
#include "cmMakefile.h"
|
||||||
#include "cmXMLSafe.h"
|
#include "cmXMLSafe.h"
|
||||||
|
@ -124,61 +125,8 @@ public:
|
||||||
|
|
||||||
#define BOUNDS_CHECKER_MARKER \
|
#define BOUNDS_CHECKER_MARKER \
|
||||||
"******######*****Begin BOUNDS CHECKER XML******######******"
|
"******######*****Begin BOUNDS CHECKER XML******######******"
|
||||||
//----------------------------------------------------------------------
|
|
||||||
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()
|
cmCTestMemCheckHandler::cmCTestMemCheckHandler()
|
||||||
|
@ -186,12 +134,14 @@ cmCTestMemCheckHandler::cmCTestMemCheckHandler()
|
||||||
this->MemCheck = true;
|
this->MemCheck = true;
|
||||||
this->CustomMaximumPassedTestOutputSize = 0;
|
this->CustomMaximumPassedTestOutputSize = 0;
|
||||||
this->CustomMaximumFailedTestOutputSize = 0;
|
this->CustomMaximumFailedTestOutputSize = 0;
|
||||||
|
this->LogWithPID = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
void cmCTestMemCheckHandler::Initialize()
|
void cmCTestMemCheckHandler::Initialize()
|
||||||
{
|
{
|
||||||
this->Superclass::Initialize();
|
this->Superclass::Initialize();
|
||||||
|
this->LogWithPID = false;
|
||||||
this->CustomMaximumPassedTestOutputSize = 0;
|
this->CustomMaximumPassedTestOutputSize = 0;
|
||||||
this->CustomMaximumFailedTestOutputSize = 0;
|
this->CustomMaximumFailedTestOutputSize = 0;
|
||||||
this->MemoryTester = "";
|
this->MemoryTester = "";
|
||||||
|
@ -199,12 +149,6 @@ void cmCTestMemCheckHandler::Initialize()
|
||||||
this->MemoryTesterOptions.clear();
|
this->MemoryTesterOptions.clear();
|
||||||
this->MemoryTesterStyle = UNKNOWN;
|
this->MemoryTesterStyle = UNKNOWN;
|
||||||
this->MemoryTesterOutputFile = "";
|
this->MemoryTesterOutputFile = "";
|
||||||
int cc;
|
|
||||||
for ( cc = 0; cc < NO_MEMORY_FAULT; cc ++ )
|
|
||||||
{
|
|
||||||
this->MemoryTesterGlobalResults[cc] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
@ -249,8 +193,8 @@ void cmCTestMemCheckHandler::GenerateTestCommand(
|
||||||
index = stream.str();
|
index = stream.str();
|
||||||
for ( pp = 0; pp < this->MemoryTesterDynamicOptions.size(); pp ++ )
|
for ( pp = 0; pp < this->MemoryTesterDynamicOptions.size(); pp ++ )
|
||||||
{
|
{
|
||||||
std::string arg = this->MemoryTesterDynamicOptions[pp];
|
std::string arg = this->MemoryTesterDynamicOptions[pp];
|
||||||
std::string::size_type pos = arg.find("??");
|
std::string::size_type pos = arg.find("??");
|
||||||
if (pos != std::string::npos)
|
if (pos != std::string::npos)
|
||||||
{
|
{
|
||||||
arg.replace(pos, 2, index);
|
arg.replace(pos, 2, index);
|
||||||
|
@ -260,17 +204,124 @@ void cmCTestMemCheckHandler::GenerateTestCommand(
|
||||||
memcheckcommand += arg;
|
memcheckcommand += arg;
|
||||||
memcheckcommand += "\"";
|
memcheckcommand += "\"";
|
||||||
}
|
}
|
||||||
|
// Create a copy of the memory tester environment variable.
|
||||||
|
// This is used for memory testing programs that pass options
|
||||||
|
// via environment varaibles.
|
||||||
|
std::string memTesterEnvironmentVariable =
|
||||||
|
this->MemoryTesterEnvironmentVariable;
|
||||||
for ( pp = 0; pp < this->MemoryTesterOptions.size(); pp ++ )
|
for ( pp = 0; pp < this->MemoryTesterOptions.size(); pp ++ )
|
||||||
{
|
{
|
||||||
args.push_back(this->MemoryTesterOptions[pp]);
|
if(memTesterEnvironmentVariable.size())
|
||||||
memcheckcommand += " \"";
|
{
|
||||||
memcheckcommand += this->MemoryTesterOptions[pp];
|
// If we are using env to pass options, append all the options to
|
||||||
memcheckcommand += "\"";
|
// this string with space separation.
|
||||||
|
memTesterEnvironmentVariable += " " + this->MemoryTesterOptions[pp];
|
||||||
|
}
|
||||||
|
// for regular options just add them to args and memcheckcommand
|
||||||
|
// which is just used for display
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.push_back(this->MemoryTesterOptions[pp]);
|
||||||
|
memcheckcommand += " \"";
|
||||||
|
memcheckcommand += this->MemoryTesterOptions[pp];
|
||||||
|
memcheckcommand += "\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if this is an env option type, then add the env string as a single
|
||||||
|
// argument.
|
||||||
|
if(memTesterEnvironmentVariable.size())
|
||||||
|
{
|
||||||
|
std::string::size_type pos = memTesterEnvironmentVariable.find("??");
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
memTesterEnvironmentVariable.replace(pos, 2, index);
|
||||||
|
}
|
||||||
|
memcheckcommand += " " + memTesterEnvironmentVariable;
|
||||||
|
args.push_back(memTesterEnvironmentVariable);
|
||||||
}
|
}
|
||||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Memory check command: "
|
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Memory check command: "
|
||||||
<< memcheckcommand << std::endl);
|
<< memcheckcommand << std::endl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
void cmCTestMemCheckHandler::InitializeResultsVectors()
|
||||||
|
{
|
||||||
|
// fill these members
|
||||||
|
// cmsys::vector<std::string> ResultStrings;
|
||||||
|
// cmsys::vector<std::string> ResultStringsLong;
|
||||||
|
// cmsys::vector<int> GlobalResults;
|
||||||
|
this->ResultStringsLong.clear();
|
||||||
|
this->ResultStrings.clear();
|
||||||
|
this->GlobalResults.clear();
|
||||||
|
// If we are working with style checkers that dynamically fill
|
||||||
|
// the results strings then return.
|
||||||
|
if(this->MemoryTesterStyle > cmCTestMemCheckHandler::BOUNDS_CHECKER)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// define the standard set of errors
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
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
|
||||||
|
};
|
||||||
|
this->GlobalResults.clear();
|
||||||
|
for(int i =0; cmCTestMemCheckResultStrings[i] != 0; ++i)
|
||||||
|
{
|
||||||
|
this->ResultStrings.push_back(cmCTestMemCheckResultStrings[i]);
|
||||||
|
this->ResultStringsLong.push_back(cmCTestMemCheckResultLongStrings[i]);
|
||||||
|
this->GlobalResults.push_back(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile *mf)
|
void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile *mf)
|
||||||
{
|
{
|
||||||
|
@ -283,6 +334,8 @@ void cmCTestMemCheckHandler::PopulateCustomVectors(cmMakefile *mf)
|
||||||
this->CTest->PopulateCustomVector(mf,
|
this->CTest->PopulateCustomVector(mf,
|
||||||
"CTEST_CUSTOM_MEMCHECK_IGNORE",
|
"CTEST_CUSTOM_MEMCHECK_IGNORE",
|
||||||
this->CustomTestsIgnore);
|
this->CustomTestsIgnore);
|
||||||
|
this->CTest->SetCTestConfigurationFromCMakeVariable(
|
||||||
|
mf, "CMakeCommand", "CMAKE_COMMAND");
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
@ -292,7 +345,6 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->CTest->StartXML(os, this->AppendXML);
|
this->CTest->StartXML(os, this->AppendXML);
|
||||||
os << "<DynamicAnalysis Checker=\"";
|
os << "<DynamicAnalysis Checker=\"";
|
||||||
switch ( this->MemoryTesterStyle )
|
switch ( this->MemoryTesterStyle )
|
||||||
|
@ -306,6 +358,9 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
|
||||||
case cmCTestMemCheckHandler::BOUNDS_CHECKER:
|
case cmCTestMemCheckHandler::BOUNDS_CHECKER:
|
||||||
os << "BoundsChecker";
|
os << "BoundsChecker";
|
||||||
break;
|
break;
|
||||||
|
case cmCTestMemCheckHandler::THREAD_SANITIZER:
|
||||||
|
os << "ThreadSanitizer";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
os << "Unknown";
|
os << "Unknown";
|
||||||
}
|
}
|
||||||
|
@ -333,8 +388,7 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
|
||||||
{
|
{
|
||||||
cmCTestTestResult *result = &this->TestResults[cc];
|
cmCTestTestResult *result = &this->TestResults[cc];
|
||||||
std::string memcheckstr;
|
std::string memcheckstr;
|
||||||
int memcheckresults[cmCTestMemCheckHandler::NO_MEMORY_FAULT];
|
std::vector<int> memcheckresults(this->ResultStrings.size(), 0);
|
||||||
int kk;
|
|
||||||
bool res = this->ProcessMemCheckOutput(result->Output, memcheckstr,
|
bool res = this->ProcessMemCheckOutput(result->Output, memcheckstr,
|
||||||
memcheckresults);
|
memcheckresults);
|
||||||
if ( res && result->Status == cmCTestMemCheckHandler::COMPLETED )
|
if ( res && result->Status == cmCTestMemCheckHandler::COMPLETED )
|
||||||
|
@ -345,16 +399,17 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
|
||||||
static_cast<size_t>(this->CustomMaximumFailedTestOutputSize));
|
static_cast<size_t>(this->CustomMaximumFailedTestOutputSize));
|
||||||
this->WriteTestResultHeader(os, result);
|
this->WriteTestResultHeader(os, result);
|
||||||
os << "\t\t<Results>" << std::endl;
|
os << "\t\t<Results>" << std::endl;
|
||||||
for ( kk = 0; cmCTestMemCheckResultLongStrings[kk]; kk ++ )
|
for(std::vector<int>::size_type kk = 0;
|
||||||
|
kk < memcheckresults.size(); ++kk)
|
||||||
{
|
{
|
||||||
if ( memcheckresults[kk] )
|
if ( memcheckresults[kk] )
|
||||||
{
|
{
|
||||||
os << "\t\t\t<Defect type=\"" << cmCTestMemCheckResultLongStrings[kk]
|
os << "\t\t\t<Defect type=\"" << this->ResultStringsLong[kk]
|
||||||
<< "\">"
|
<< "\">"
|
||||||
<< memcheckresults[kk]
|
<< memcheckresults[kk]
|
||||||
<< "</Defect>" << std::endl;
|
<< "</Defect>" << std::endl;
|
||||||
}
|
}
|
||||||
this->MemoryTesterGlobalResults[kk] += memcheckresults[kk];
|
this->GlobalResults[kk] += memcheckresults[kk];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string logTag;
|
std::string logTag;
|
||||||
|
@ -383,9 +438,9 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
|
||||||
cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory checking results:"
|
cmCTestLog(this->CTest, HANDLER_OUTPUT, "Memory checking results:"
|
||||||
<< std::endl);
|
<< std::endl);
|
||||||
os << "\t<DefectList>" << std::endl;
|
os << "\t<DefectList>" << std::endl;
|
||||||
for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
|
for ( cc = 0; cc < this->GlobalResults.size(); cc ++ )
|
||||||
{
|
{
|
||||||
if ( this->MemoryTesterGlobalResults[cc] )
|
if ( this->GlobalResults[cc] )
|
||||||
{
|
{
|
||||||
#ifdef cerr
|
#ifdef cerr
|
||||||
# undef cerr
|
# undef cerr
|
||||||
|
@ -393,9 +448,9 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
|
||||||
std::cerr.width(35);
|
std::cerr.width(35);
|
||||||
#define cerr no_cerr
|
#define cerr no_cerr
|
||||||
cmCTestLog(this->CTest, HANDLER_OUTPUT,
|
cmCTestLog(this->CTest, HANDLER_OUTPUT,
|
||||||
cmCTestMemCheckResultLongStrings[cc] << " - "
|
this->ResultStringsLong[cc] << " - "
|
||||||
<< this->MemoryTesterGlobalResults[cc] << std::endl);
|
<< this->GlobalResults[cc] << std::endl);
|
||||||
os << "\t\t<Defect Type=\"" << cmCTestMemCheckResultLongStrings[cc]
|
os << "\t\t<Defect Type=\"" << this->ResultStringsLong[cc]
|
||||||
<< "\"/>" << std::endl;
|
<< "\"/>" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -410,13 +465,13 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
|
||||||
|
|
||||||
os << "</DynamicAnalysis>" << std::endl;
|
os << "</DynamicAnalysis>" << std::endl;
|
||||||
this->CTest->EndXML(os);
|
this->CTest->EndXML(os);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
bool cmCTestMemCheckHandler::InitializeMemoryChecking()
|
bool cmCTestMemCheckHandler::InitializeMemoryChecking()
|
||||||
{
|
{
|
||||||
|
this->MemoryTesterEnvironmentVariable = "";
|
||||||
|
this->MemoryTester = "";
|
||||||
// Setup the command
|
// Setup the command
|
||||||
if ( cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
|
if ( cmSystemTools::FileExists(this->CTest->GetCTestConfiguration(
|
||||||
"MemoryCheckCommand").c_str()) )
|
"MemoryCheckCommand").c_str()) )
|
||||||
|
@ -426,7 +481,9 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
|
||||||
std::string testerName =
|
std::string testerName =
|
||||||
cmSystemTools::GetFilenameName(this->MemoryTester);
|
cmSystemTools::GetFilenameName(this->MemoryTester);
|
||||||
// determine the checker type
|
// determine the checker type
|
||||||
if ( testerName.find("valgrind") != std::string::npos )
|
if ( testerName.find("valgrind") != std::string::npos ||
|
||||||
|
this->CTest->GetCTestConfiguration("MemoryCheckType")
|
||||||
|
== "Valgrind")
|
||||||
{
|
{
|
||||||
this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
|
this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
|
||||||
}
|
}
|
||||||
|
@ -464,12 +521,38 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
|
||||||
= this->CTest->GetCTestConfiguration("BoundsCheckerCommand").c_str();
|
= this->CTest->GetCTestConfiguration("BoundsCheckerCommand").c_str();
|
||||||
this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
|
this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
|
||||||
}
|
}
|
||||||
else
|
if ( this->CTest->GetCTestConfiguration("MemoryCheckType")
|
||||||
|
== "ThreadSanitizer")
|
||||||
|
{
|
||||||
|
this->MemoryTester
|
||||||
|
= this->CTest->GetCTestConfiguration("CMakeCommand").c_str();
|
||||||
|
this->MemoryTesterStyle = cmCTestMemCheckHandler::THREAD_SANITIZER;
|
||||||
|
this->LogWithPID = true; // even if we give the log file the pid is added
|
||||||
|
}
|
||||||
|
// Check the MemoryCheckType
|
||||||
|
if(this->MemoryTesterStyle == cmCTestMemCheckHandler::UNKNOWN)
|
||||||
|
{
|
||||||
|
std::string checkType =
|
||||||
|
this->CTest->GetCTestConfiguration("MemoryCheckType");
|
||||||
|
if(checkType == "Purify")
|
||||||
|
{
|
||||||
|
this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
|
||||||
|
}
|
||||||
|
else if(checkType == "BoundsChecker")
|
||||||
|
{
|
||||||
|
this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
|
||||||
|
}
|
||||||
|
else if(checkType == "Valgrind")
|
||||||
|
{
|
||||||
|
this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(this->MemoryTester.size() == 0 )
|
||||||
{
|
{
|
||||||
cmCTestLog(this->CTest, WARNING,
|
cmCTestLog(this->CTest, WARNING,
|
||||||
"Memory checker (MemoryCheckCommand) "
|
"Memory checker (MemoryCheckCommand) "
|
||||||
"not set, or cannot find the specified program."
|
"not set, or cannot find the specified program."
|
||||||
<< std::endl);
|
<< std::endl);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,6 +651,20 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
|
||||||
this->MemoryTesterOptions.push_back("/M");
|
this->MemoryTesterOptions.push_back("/M");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case cmCTestMemCheckHandler::THREAD_SANITIZER:
|
||||||
|
{
|
||||||
|
// To pass arguments to ThreadSanitizer the environment variable
|
||||||
|
// TSAN_OPTIONS is used. This is done with the cmake -E env command.
|
||||||
|
// The MemoryTesterDynamicOptions is setup with the -E env
|
||||||
|
// Then the MemoryTesterEnvironmentVariable gets the
|
||||||
|
// TSAN_OPTIONS string with the log_path in it.
|
||||||
|
this->MemoryTesterDynamicOptions.push_back("-E");
|
||||||
|
this->MemoryTesterDynamicOptions.push_back("env");
|
||||||
|
std::string outputFile = "TSAN_OPTIONS=log_path=\""
|
||||||
|
+ this->MemoryTesterOutputFile + "\"";
|
||||||
|
this->MemoryTesterEnvironmentVariable = outputFile;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
cmCTestLog(this->CTest, ERROR_MESSAGE,
|
cmCTestLog(this->CTest, ERROR_MESSAGE,
|
||||||
"Do not understand memory checker: " << this->MemoryTester
|
"Do not understand memory checker: " << this->MemoryTester
|
||||||
|
@ -575,24 +672,20 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string>::size_type cc;
|
this->InitializeResultsVectors();
|
||||||
for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
|
// std::vector<std::string>::size_type cc;
|
||||||
{
|
// for ( cc = 0; cmCTestMemCheckResultStrings[cc]; cc ++ )
|
||||||
this->MemoryTesterGlobalResults[cc] = 0;
|
// {
|
||||||
}
|
// this->MemoryTesterGlobalResults[cc] = 0;
|
||||||
|
// }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str,
|
bool cmCTestMemCheckHandler::
|
||||||
std::string& log, int* results)
|
ProcessMemCheckOutput(const std::string& str,
|
||||||
|
std::string& log, std::vector<int>& results)
|
||||||
{
|
{
|
||||||
std::string::size_type cc;
|
|
||||||
for ( cc = 0; cc < cmCTestMemCheckHandler::NO_MEMORY_FAULT; cc ++ )
|
|
||||||
{
|
|
||||||
results[cc] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( this->MemoryTesterStyle == cmCTestMemCheckHandler::VALGRIND )
|
if ( this->MemoryTesterStyle == cmCTestMemCheckHandler::VALGRIND )
|
||||||
{
|
{
|
||||||
return this->ProcessMemCheckValgrindOutput(str, log, results);
|
return this->ProcessMemCheckValgrindOutput(str, log, results);
|
||||||
|
@ -601,6 +694,11 @@ bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str,
|
||||||
{
|
{
|
||||||
return this->ProcessMemCheckPurifyOutput(str, log, results);
|
return this->ProcessMemCheckPurifyOutput(str, log, results);
|
||||||
}
|
}
|
||||||
|
else if ( this->MemoryTesterStyle ==
|
||||||
|
cmCTestMemCheckHandler::THREAD_SANITIZER )
|
||||||
|
{
|
||||||
|
return this->ProcessMemCheckThreadSanitizerOutput(str, log, results);
|
||||||
|
}
|
||||||
else if ( this->MemoryTesterStyle ==
|
else if ( this->MemoryTesterStyle ==
|
||||||
cmCTestMemCheckHandler::BOUNDS_CHECKER )
|
cmCTestMemCheckHandler::BOUNDS_CHECKER )
|
||||||
{
|
{
|
||||||
|
@ -612,15 +710,68 @@ bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str,
|
||||||
log.append("None that I know");
|
log.append("None that I know");
|
||||||
log = str;
|
log = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<int>::size_type cmCTestMemCheckHandler::FindOrAddWarning(
|
||||||
|
const std::string& warning)
|
||||||
|
{
|
||||||
|
for(std::vector<std::string>::size_type i =0;
|
||||||
|
i < this->ResultStrings.size(); ++i)
|
||||||
|
{
|
||||||
|
if(this->ResultStrings[i] == warning)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->GlobalResults.push_back(0); // this must stay the same size
|
||||||
|
this->ResultStrings.push_back(warning);
|
||||||
|
this->ResultStringsLong.push_back(warning);
|
||||||
|
return this->ResultStrings.size()-1;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
bool cmCTestMemCheckHandler::ProcessMemCheckThreadSanitizerOutput(
|
||||||
|
const std::string& str, std::string& log,
|
||||||
|
std::vector<int>& result)
|
||||||
|
{
|
||||||
|
cmsys::RegularExpression
|
||||||
|
sanitizerWarning("WARNING: ThreadSanitizer: (.*) \\(pid=.*\\)");
|
||||||
|
int defects = 0;
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
cmSystemTools::Split(str.c_str(), lines);
|
||||||
|
cmOStringStream ostr;
|
||||||
|
log = "";
|
||||||
|
for( std::vector<std::string>::iterator i = lines.begin();
|
||||||
|
i != lines.end(); ++i)
|
||||||
|
{
|
||||||
|
if(sanitizerWarning.find(*i))
|
||||||
|
{
|
||||||
|
std::string warning = sanitizerWarning.match(1);
|
||||||
|
std::vector<int>::size_type idx = this->FindOrAddWarning(warning);
|
||||||
|
if(result.size() == 0 || idx > result.size()-1)
|
||||||
|
{
|
||||||
|
result.push_back(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result[idx]++;
|
||||||
|
}
|
||||||
|
defects++;
|
||||||
|
ostr << "<b>" << this->ResultStrings[idx] << "</b> ";
|
||||||
|
}
|
||||||
|
ostr << cmXMLSafe(*i) << std::endl;
|
||||||
|
}
|
||||||
|
log = ostr.str();
|
||||||
|
if(defects)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
|
bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
|
||||||
const std::string& str, std::string& log,
|
const std::string& str, std::string& log,
|
||||||
int* results)
|
std::vector<int>& results)
|
||||||
{
|
{
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
cmSystemTools::Split(str.c_str(), lines);
|
cmSystemTools::Split(str.c_str(), lines);
|
||||||
|
@ -634,19 +785,19 @@ bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
|
||||||
for( std::vector<std::string>::iterator i = lines.begin();
|
for( std::vector<std::string>::iterator i = lines.begin();
|
||||||
i != lines.end(); ++i)
|
i != lines.end(); ++i)
|
||||||
{
|
{
|
||||||
int failure = cmCTestMemCheckHandler::NO_MEMORY_FAULT;
|
std::vector<int>::size_type failure = this->ResultStrings.size();
|
||||||
if ( pfW.find(*i) )
|
if ( pfW.find(*i) )
|
||||||
{
|
{
|
||||||
int cc;
|
std::vector<int>::size_type cc;
|
||||||
for ( cc = 0; cc < cmCTestMemCheckHandler::NO_MEMORY_FAULT; cc ++ )
|
for ( cc = 0; cc < this->ResultStrings.size(); cc ++ )
|
||||||
{
|
{
|
||||||
if ( pfW.match(1) == cmCTestMemCheckResultStrings[cc] )
|
if ( pfW.match(1) == this->ResultStrings[cc] )
|
||||||
{
|
{
|
||||||
failure = cc;
|
failure = cc;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( cc == cmCTestMemCheckHandler::NO_MEMORY_FAULT )
|
if ( cc == this->ResultStrings.size() )
|
||||||
{
|
{
|
||||||
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown Purify memory fault: "
|
cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown Purify memory fault: "
|
||||||
<< pfW.match(1) << std::endl);
|
<< pfW.match(1) << std::endl);
|
||||||
|
@ -654,9 +805,9 @@ bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( failure != NO_MEMORY_FAULT )
|
if ( failure != this->ResultStrings.size() )
|
||||||
{
|
{
|
||||||
ostr << "<b>" << cmCTestMemCheckResultStrings[failure] << "</b> ";
|
ostr << "<b>" << this->ResultStrings[failure] << "</b> ";
|
||||||
results[failure] ++;
|
results[failure] ++;
|
||||||
defects ++;
|
defects ++;
|
||||||
}
|
}
|
||||||
|
@ -674,7 +825,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckPurifyOutput(
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
|
bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
|
||||||
const std::string& str, std::string& log,
|
const std::string& str, std::string& log,
|
||||||
int* results)
|
std::vector<int>& results)
|
||||||
{
|
{
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
cmSystemTools::Split(str.c_str(), lines);
|
cmSystemTools::Split(str.c_str(), lines);
|
||||||
|
@ -803,7 +954,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
|
||||||
|
|
||||||
if ( failure != cmCTestMemCheckHandler::NO_MEMORY_FAULT )
|
if ( failure != cmCTestMemCheckHandler::NO_MEMORY_FAULT )
|
||||||
{
|
{
|
||||||
ostr << "<b>" << cmCTestMemCheckResultStrings[failure] << "</b> ";
|
ostr << "<b>" << this->ResultStrings[failure] << "</b> ";
|
||||||
results[failure] ++;
|
results[failure] ++;
|
||||||
defects ++;
|
defects ++;
|
||||||
}
|
}
|
||||||
|
@ -855,7 +1006,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput(
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
|
bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
|
||||||
const std::string& str, std::string& log,
|
const std::string& str, std::string& log,
|
||||||
int* results)
|
std::vector<int>& results)
|
||||||
{
|
{
|
||||||
log = "";
|
log = "";
|
||||||
double sttime = cmSystemTools::GetTime();
|
double sttime = cmSystemTools::GetTime();
|
||||||
|
@ -909,6 +1060,26 @@ bool cmCTestMemCheckHandler::ProcessMemCheckBoundsCheckerOutput(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PostProcessTest memcheck results
|
||||||
|
void
|
||||||
|
cmCTestMemCheckHandler::PostProcessTest(cmCTestTestResult& res,
|
||||||
|
int test)
|
||||||
|
{
|
||||||
|
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
||||||
|
"PostProcessTest memcheck results for : "
|
||||||
|
<< res.Name << std::endl);
|
||||||
|
if(this->MemoryTesterStyle
|
||||||
|
== cmCTestMemCheckHandler::BOUNDS_CHECKER)
|
||||||
|
{
|
||||||
|
this->PostProcessBoundsCheckerTest(res, test);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->AppendMemTesterOutput(res, test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// This method puts the bounds checker output file into the output
|
// This method puts the bounds checker output file into the output
|
||||||
// for the test
|
// for the test
|
||||||
void
|
void
|
||||||
|
@ -950,36 +1121,17 @@ cmCTestMemCheckHandler::PostProcessBoundsCheckerTest(cmCTestTestResult& res,
|
||||||
<< this->BoundsCheckerXMLFile << std::endl);
|
<< this->BoundsCheckerXMLFile << std::endl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
cmCTestMemCheckHandler::PostProcessPurifyTest(cmCTestTestResult& res,
|
|
||||||
int test)
|
|
||||||
{
|
|
||||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
|
||||||
"PostProcessPurifyTest for : "
|
|
||||||
<< res.Name << std::endl);
|
|
||||||
this->AppendMemTesterOutput(res, test);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
cmCTestMemCheckHandler::PostProcessValgrindTest(cmCTestTestResult& res,
|
|
||||||
int test)
|
|
||||||
{
|
|
||||||
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
|
|
||||||
"PostProcessValgrindTest for : "
|
|
||||||
<< res.Name << std::endl);
|
|
||||||
this->AppendMemTesterOutput(res, test);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
cmCTestMemCheckHandler::AppendMemTesterOutput(cmCTestTestResult& res,
|
cmCTestMemCheckHandler::AppendMemTesterOutput(cmCTestTestResult& res,
|
||||||
int test)
|
int test)
|
||||||
{
|
{
|
||||||
std::string ofile = this->TestOutputFileName(test);
|
std::string ofile = this->TestOutputFileName(test);
|
||||||
|
|
||||||
if ( ofile.empty() )
|
if ( ofile.empty() )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// put ifs in scope so file can be deleted if needed
|
||||||
|
{
|
||||||
cmsys::ifstream ifs(ofile.c_str());
|
cmsys::ifstream ifs(ofile.c_str());
|
||||||
if ( !ifs )
|
if ( !ifs )
|
||||||
{
|
{
|
||||||
|
@ -993,6 +1145,12 @@ cmCTestMemCheckHandler::AppendMemTesterOutput(cmCTestTestResult& res,
|
||||||
res.Output += line;
|
res.Output += line;
|
||||||
res.Output += "\n";
|
res.Output += "\n";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if(this->LogWithPID)
|
||||||
|
{
|
||||||
|
cmSystemTools::RemoveFile(ofile.c_str());
|
||||||
|
cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Remove: "<< ofile <<"\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
|
@ -1005,14 +1163,29 @@ cmCTestMemCheckHandler::TestOutputFileName(int test)
|
||||||
std::string ofile = this->MemoryTesterOutputFile;
|
std::string ofile = this->MemoryTesterOutputFile;
|
||||||
std::string::size_type pos = ofile.find("??");
|
std::string::size_type pos = ofile.find("??");
|
||||||
ofile.replace(pos, 2, index);
|
ofile.replace(pos, 2, index);
|
||||||
|
if(this->LogWithPID)
|
||||||
if ( !cmSystemTools::FileExists(ofile.c_str()) )
|
{
|
||||||
|
ofile += ".*";
|
||||||
|
cmsys::Glob g;
|
||||||
|
g.FindFiles(ofile);
|
||||||
|
if(g.GetFiles().size() == 0)
|
||||||
|
{
|
||||||
|
std::string log = "Cannot find memory tester output file: "
|
||||||
|
+ ofile;
|
||||||
|
cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
|
||||||
|
ofile = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ofile = g.GetFiles()[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( !cmSystemTools::FileExists(ofile.c_str()) )
|
||||||
{
|
{
|
||||||
std::string log = "Cannot find memory tester output file: "
|
std::string log = "Cannot find memory tester output file: "
|
||||||
+ ofile;
|
+ ofile;
|
||||||
cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
|
cmCTestLog(this->CTest, ERROR_MESSAGE, log.c_str() << std::endl);
|
||||||
ofile = "";
|
ofile = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return ofile;
|
return ofile;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,10 @@
|
||||||
|
|
||||||
|
|
||||||
#include "cmCTestTestHandler.h"
|
#include "cmCTestTestHandler.h"
|
||||||
|
#include "cmStandardIncludes.h"
|
||||||
#include "cmListFileCache.h"
|
#include "cmListFileCache.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
class cmMakefile;
|
class cmMakefile;
|
||||||
|
|
||||||
|
@ -45,7 +48,9 @@ private:
|
||||||
UNKNOWN = 0,
|
UNKNOWN = 0,
|
||||||
VALGRIND,
|
VALGRIND,
|
||||||
PURIFY,
|
PURIFY,
|
||||||
BOUNDS_CHECKER
|
BOUNDS_CHECKER,
|
||||||
|
// checkers after hear do not use the standard error list
|
||||||
|
THREAD_SANITIZER
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
enum { // Memory faults
|
enum { // Memory faults
|
||||||
|
@ -93,7 +98,17 @@ private:
|
||||||
std::vector<std::string> MemoryTesterOptions;
|
std::vector<std::string> MemoryTesterOptions;
|
||||||
int MemoryTesterStyle;
|
int MemoryTesterStyle;
|
||||||
std::string MemoryTesterOutputFile;
|
std::string MemoryTesterOutputFile;
|
||||||
int MemoryTesterGlobalResults[NO_MEMORY_FAULT];
|
std::string MemoryTesterEnvironmentVariable;
|
||||||
|
// these are used to store the types of errors that can show up
|
||||||
|
std::vector<std::string> ResultStrings;
|
||||||
|
std::vector<std::string> ResultStringsLong;
|
||||||
|
std::vector<int> GlobalResults;
|
||||||
|
bool LogWithPID; // does log file add pid
|
||||||
|
|
||||||
|
std::vector<int>::size_type FindOrAddWarning(const std::string& warning);
|
||||||
|
// initialize the ResultStrings and ResultStringsLong for
|
||||||
|
// this type of checker
|
||||||
|
void InitializeResultsVectors();
|
||||||
|
|
||||||
///! Initialize memory checking subsystem.
|
///! Initialize memory checking subsystem.
|
||||||
bool InitializeMemoryChecking();
|
bool InitializeMemoryChecking();
|
||||||
|
@ -110,17 +125,22 @@ private:
|
||||||
//string. After running, log holds the output and results hold the
|
//string. After running, log holds the output and results hold the
|
||||||
//different memmory errors.
|
//different memmory errors.
|
||||||
bool ProcessMemCheckOutput(const std::string& str,
|
bool ProcessMemCheckOutput(const std::string& str,
|
||||||
std::string& log, int* results);
|
std::string& log, std::vector<int>& results);
|
||||||
bool ProcessMemCheckValgrindOutput(const std::string& str,
|
bool ProcessMemCheckValgrindOutput(const std::string& str,
|
||||||
std::string& log, int* results);
|
std::string& log,
|
||||||
|
std::vector<int>& results);
|
||||||
bool ProcessMemCheckPurifyOutput(const std::string& str,
|
bool ProcessMemCheckPurifyOutput(const std::string& str,
|
||||||
std::string& log, int* results);
|
std::string& log,
|
||||||
|
std::vector<int>& results);
|
||||||
|
bool ProcessMemCheckThreadSanitizerOutput(const std::string& str,
|
||||||
|
std::string& log,
|
||||||
|
std::vector<int>& results);
|
||||||
bool ProcessMemCheckBoundsCheckerOutput(const std::string& str,
|
bool ProcessMemCheckBoundsCheckerOutput(const std::string& str,
|
||||||
std::string& log, int* results);
|
std::string& log,
|
||||||
|
std::vector<int>& results);
|
||||||
|
|
||||||
void PostProcessPurifyTest(cmCTestTestResult& res, int test);
|
void PostProcessTest(cmCTestTestResult& res, int test);
|
||||||
void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test);
|
void PostProcessBoundsCheckerTest(cmCTestTestResult& res, int test);
|
||||||
void PostProcessValgrindTest(cmCTestTestResult& res, int test);
|
|
||||||
|
|
||||||
///! append MemoryTesterOutputFile to the test log
|
///! append MemoryTesterOutputFile to the test log
|
||||||
void AppendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res,
|
void AppendMemTesterOutput(cmCTestTestHandler::cmCTestTestResult& res,
|
||||||
|
|
|
@ -392,20 +392,7 @@ void cmCTestRunTest::MemCheckPostProcess()
|
||||||
<< this->TestResult.Name << std::endl);
|
<< this->TestResult.Name << std::endl);
|
||||||
cmCTestMemCheckHandler * handler = static_cast<cmCTestMemCheckHandler*>
|
cmCTestMemCheckHandler * handler = static_cast<cmCTestMemCheckHandler*>
|
||||||
(this->TestHandler);
|
(this->TestHandler);
|
||||||
switch ( handler->MemoryTesterStyle )
|
handler->PostProcessTest(this->TestResult, this->Index);
|
||||||
{
|
|
||||||
case cmCTestMemCheckHandler::VALGRIND:
|
|
||||||
handler->PostProcessValgrindTest(this->TestResult, this->Index);
|
|
||||||
break;
|
|
||||||
case cmCTestMemCheckHandler::PURIFY:
|
|
||||||
handler->PostProcessPurifyTest(this->TestResult, this->Index);
|
|
||||||
break;
|
|
||||||
case cmCTestMemCheckHandler::BOUNDS_CHECKER:
|
|
||||||
handler->PostProcessBoundsCheckerTest(this->TestResult, this->Index);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
|
@ -103,6 +103,19 @@ unset(CTEST_EXTRA_CONFIG)
|
||||||
unset(CTEST_EXTRA_CODE)
|
unset(CTEST_EXTRA_CODE)
|
||||||
unset(CMAKELISTS_EXTRA_CODE)
|
unset(CMAKELISTS_EXTRA_CODE)
|
||||||
|
|
||||||
|
# add ThreadSanitizer test
|
||||||
|
set(CTEST_EXTRA_CODE
|
||||||
|
"set(CTEST_MEMORYCHECK_COMMAND_OPTIONS \"report_bugs=1 history_size=5 exitcode=55\")
|
||||||
|
")
|
||||||
|
|
||||||
|
set(CMAKELISTS_EXTRA_CODE
|
||||||
|
"add_test(NAME TestSan COMMAND \"${CMAKE_COMMAND}\"
|
||||||
|
-P \"${CMAKE_CURRENT_SOURCE_DIR}/testThreadSanitizer.cmake\")
|
||||||
|
")
|
||||||
|
gen_mc_test_internal(DummyThreadSanitizer "" -DMEMCHECK_TYPE=ThreadSanitizer)
|
||||||
|
set(CMAKELISTS_EXTRA_CODE )
|
||||||
|
set(CTEST_EXTRA_CODE)
|
||||||
|
|
||||||
gen_mc_test(DummyPurify "\${PSEUDO_PURIFY}")
|
gen_mc_test(DummyPurify "\${PSEUDO_PURIFY}")
|
||||||
gen_mc_test(DummyValgrind "\${PSEUDO_VALGRIND}")
|
gen_mc_test(DummyValgrind "\${PSEUDO_VALGRIND}")
|
||||||
gen_mc_test(DummyBC "\${PSEUDO_BC}")
|
gen_mc_test(DummyBC "\${PSEUDO_BC}")
|
||||||
|
@ -189,6 +202,11 @@ set_tests_properties(CTestTestMemcheckDummyValgrindTwoTargets PROPERTIES
|
||||||
PASS_REGULAR_EXPRESSION
|
PASS_REGULAR_EXPRESSION
|
||||||
"\nMemory check project ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets\n.*\n *Start 1: RunCMake\n(.*\n)?Memory check command: .* \"--log-file=${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets/Testing/Temporary/MemoryChecker.1.log\" \"-q\".*\n *Start 2: RunCMakeAgain\n(.*\n)?Memory check command: .* \"--log-file=${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets/Testing/Temporary/MemoryChecker.2.log\" \"-q\".*\n")
|
"\nMemory check project ${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets\n.*\n *Start 1: RunCMake\n(.*\n)?Memory check command: .* \"--log-file=${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets/Testing/Temporary/MemoryChecker.1.log\" \"-q\".*\n *Start 2: RunCMakeAgain\n(.*\n)?Memory check command: .* \"--log-file=${CTEST_ESCAPED_CMAKE_CURRENT_BINARY_DIR}/DummyValgrindTwoTargets/Testing/Temporary/MemoryChecker.2.log\" \"-q\".*\n")
|
||||||
|
|
||||||
|
set_tests_properties(CTestTestMemcheckDummyThreadSanitizer PROPERTIES
|
||||||
|
PASS_REGULAR_EXPRESSION
|
||||||
|
".*Memory checking results:.*data race.* - 1.*data race on vptr .ctor/dtor vs virtual call. - 1.*heap-use-after-free - 1.*thread leak - 1.*destroy of a locked mutex - 1.*double lock of a mutex - 1.*unlock of an unlocked mutex .or by a wrong thread. - 1.*read lock of a write locked mutex - 1.*read unlock of a write locked mutex - 1.*signal-unsafe call inside of a signal - 1.*signal handler spoils errno - 1.*lock-order-inversion .potential deadlock. - 1.*")
|
||||||
|
|
||||||
|
|
||||||
# Xcode 2.x forgets to create the output directory before linking
|
# Xcode 2.x forgets to create the output directory before linking
|
||||||
# the individual architectures.
|
# the individual architectures.
|
||||||
if(CMAKE_OSX_ARCHITECTURES AND XCODE AND NOT "${XCODE_VERSION}" MATCHES "^[^12]")
|
if(CMAKE_OSX_ARCHITECTURES AND XCODE AND NOT "${XCODE_VERSION}" MATCHES "^[^12]")
|
||||||
|
|
|
@ -15,6 +15,7 @@ set(CTEST_COVERAGE_COMMAND "@COVERAGE_COMMAND@")
|
||||||
set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
|
set(CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}")
|
||||||
|
|
||||||
set(CTEST_MEMORYCHECK_COMMAND "@CHECKER_COMMAND@")
|
set(CTEST_MEMORYCHECK_COMMAND "@CHECKER_COMMAND@")
|
||||||
|
set(CTEST_MEMORYCHECK_TYPE "${MEMCHECK_TYPE}")
|
||||||
|
|
||||||
@CTEST_EXTRA_CODE@
|
@CTEST_EXTRA_CODE@
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
# this file simulates a program that has been built with thread sanitizer
|
||||||
|
# options
|
||||||
|
|
||||||
|
message("TSAN_OPTIONS = [$ENV{TSAN_OPTIONS}]")
|
||||||
|
string(REGEX REPLACE ".*log_path=\"([^\"]*)\".*" "\\1" LOG_FILE "$ENV{TSAN_OPTIONS}")
|
||||||
|
message("LOG_FILE=[${LOG_FILE}]")
|
||||||
|
|
||||||
|
set(error_types
|
||||||
|
"data race"
|
||||||
|
"data race on vptr (ctor/dtor vs virtual call)"
|
||||||
|
"heap-use-after-free"
|
||||||
|
"thread leak"
|
||||||
|
"destroy of a locked mutex"
|
||||||
|
"double lock of a mutex"
|
||||||
|
"unlock of an unlocked mutex (or by a wrong thread)"
|
||||||
|
"read lock of a write locked mutex"
|
||||||
|
"read unlock of a write locked mutex"
|
||||||
|
"signal-unsafe call inside of a signal"
|
||||||
|
"signal handler spoils errno"
|
||||||
|
"lock-order-inversion (potential deadlock)"
|
||||||
|
)
|
||||||
|
|
||||||
|
# clear the log file
|
||||||
|
file(REMOVE "${LOG_FILE}.2343")
|
||||||
|
|
||||||
|
# create an error of each type of thread santizer
|
||||||
|
# these names come from tsan_report.cc in llvm
|
||||||
|
foreach(error_type ${error_types} )
|
||||||
|
|
||||||
|
file(APPEND "${LOG_FILE}.2343"
|
||||||
|
"==================
|
||||||
|
WARNING: ThreadSanitizer: ${error_type} (pid=27978)
|
||||||
|
Write of size 4 at 0x7fe017ce906c by thread T1:
|
||||||
|
#0 Thread1 ??:0 (exe+0x000000000bb0)
|
||||||
|
#1 <null> <null>:0 (libtsan.so.0+0x00000001b279)
|
||||||
|
|
||||||
|
Previous write of size 4 at 0x7fe017ce906c by main thread:
|
||||||
|
#0 main ??:0 (exe+0x000000000c3c)
|
||||||
|
|
||||||
|
Thread T1 (tid=27979, running) created by main thread at:
|
||||||
|
#0 <null> <null>:0 (libtsan.so.0+0x00000001ed7b)
|
||||||
|
#1 main ??:0 (exe+0x000000000c2c)
|
||||||
|
|
||||||
|
SUMMARY: ThreadSanitizer: ${error_type} ??:0 Thread1
|
||||||
|
==================
|
||||||
|
")
|
||||||
|
endforeach()
|
Loading…
Reference in New Issue