Merge topic 'thread-sanitizer'
7c80ce6f
Help: Add notes for topic 'thread-sanitizer'49948f72
ctest_memcheck: Add support for ThreadSanitizer
This commit is contained in:
commit
55d3e88fb7
|
@ -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,5 @@
|
||||||
|
thread-sanitizer
|
||||||
|
----------------
|
||||||
|
|
||||||
|
* The :command:`ctest_memcheck` command learned to support
|
||||||
|
``ThreadSanitizer``.
|
|
@ -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