summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBill Hoffman <bill.hoffman@kitware.com>2014-07-14 21:01:47 (GMT)
committerBrad King <brad.king@kitware.com>2014-07-16 15:50:23 (GMT)
commit44726714322ca0b75628e234229f4583a480d7ec (patch)
tree5e5ffa1fb65bec92047096f68f0d7defe5be1108 /Source
parent49bf3e7d8daab2a1e7ba435d011618bd2c516766 (diff)
downloadCMake-44726714322ca0b75628e234229f4583a480d7ec.zip
CMake-44726714322ca0b75628e234229f4583a480d7ec.tar.gz
CMake-44726714322ca0b75628e234229f4583a480d7ec.tar.bz2
ctest_memcheck: Add support for memory and leak sanitizer.
This adds support for memory and leak sanitizers. This is built into clang and gcc 4.8 and new compilers. It is activated with a -f switch during compile.
Diffstat (limited to 'Source')
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.cxx74
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.h9
-rw-r--r--Source/cmXMLParser.cxx13
-rw-r--r--Source/cmXMLParser.h9
4 files changed, 87 insertions, 18 deletions
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
index bcf09ad..a389359 100644
--- a/Source/CTest/cmCTestMemCheckHandler.cxx
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -45,11 +45,23 @@ static CatToErrorType cmCTestMemCheckBoundsChecker[] = {
{0,0}
};
+static void xmlReportError(int line, const char* msg, void* data)
+{
+ cmCTest* ctest = (cmCTest*)data;
+ cmCTestLog(ctest, ERROR_MESSAGE,
+ "Error parsing XML in stream at line "
+ << line << ": " << msg << std::endl);
+}
+
// parse the xml file containing the results of last BoundsChecker run
class cmBoundsCheckerParser : public cmXMLParser
{
public:
- cmBoundsCheckerParser(cmCTest* c) { this->CTest = c;}
+ cmBoundsCheckerParser(cmCTest* c)
+ {
+ this->CTest = c;
+ this->SetErrorCallback(xmlReportError, (void*)c);
+ }
void StartElement(const std::string& name, const char** atts)
{
if(name == "MemoryLeak" ||
@@ -361,6 +373,9 @@ void cmCTestMemCheckHandler::GenerateDartOutput(std::ostream& os)
case cmCTestMemCheckHandler::THREAD_SANITIZER:
os << "ThreadSanitizer";
break;
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+ os << "AddressSanitizer";
+ break;
default:
os << "Unknown";
}
@@ -529,6 +544,14 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
this->MemoryTesterStyle = cmCTestMemCheckHandler::THREAD_SANITIZER;
this->LogWithPID = true; // even if we give the log file the pid is added
}
+ if ( this->CTest->GetCTestConfiguration("MemoryCheckType")
+ == "AddressSanitizer")
+ {
+ this->MemoryTester
+ = this->CTest->GetCTestConfiguration("CMakeCommand").c_str();
+ this->MemoryTesterStyle = cmCTestMemCheckHandler::ADDRESS_SANITIZER;
+ this->LogWithPID = true; // even if we give the log file the pid is added
+ }
// Check the MemoryCheckType
if(this->MemoryTesterStyle == cmCTestMemCheckHandler::UNKNOWN)
{
@@ -651,6 +674,9 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
this->MemoryTesterOptions.push_back("/M");
break;
}
+ // these two are almost the same but the env var used
+ // is different
+ case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
case cmCTestMemCheckHandler::THREAD_SANITIZER:
{
// To pass arguments to ThreadSanitizer the environment variable
@@ -660,9 +686,16 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
// 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=\""
+ std::string envVar = "TSAN_OPTIONS";
+ std::string extraOptions;
+ if(this->MemoryTesterStyle == cmCTestMemCheckHandler::ADDRESS_SANITIZER)
+ {
+ envVar = "ASAN_OPTIONS";
+ extraOptions = " detect_leaks=1";
+ }
+ std::string outputFile = envVar + "=log_path=\""
+ this->MemoryTesterOutputFile + "\"";
- this->MemoryTesterEnvironmentVariable = outputFile;
+ this->MemoryTesterEnvironmentVariable = outputFile + extraOptions;
break;
}
default:
@@ -695,9 +728,11 @@ ProcessMemCheckOutput(const std::string& str,
return this->ProcessMemCheckPurifyOutput(str, log, results);
}
else if ( this->MemoryTesterStyle ==
- cmCTestMemCheckHandler::THREAD_SANITIZER )
+ cmCTestMemCheckHandler::THREAD_SANITIZER ||
+ this->MemoryTesterStyle ==
+ cmCTestMemCheckHandler::ADDRESS_SANITIZER)
{
- return this->ProcessMemCheckThreadSanitizerOutput(str, log, results);
+ return this->ProcessMemCheckSanitizerOutput(str, log, results);
}
else if ( this->MemoryTesterStyle ==
cmCTestMemCheckHandler::BOUNDS_CHECKER )
@@ -730,12 +765,21 @@ std::vector<int>::size_type cmCTestMemCheckHandler::FindOrAddWarning(
return this->ResultStrings.size()-1;
}
//----------------------------------------------------------------------
-bool cmCTestMemCheckHandler::ProcessMemCheckThreadSanitizerOutput(
+bool cmCTestMemCheckHandler::ProcessMemCheckSanitizerOutput(
const std::string& str, std::string& log,
std::vector<int>& result)
{
- cmsys::RegularExpression
- sanitizerWarning("WARNING: ThreadSanitizer: (.*) \\(pid=.*\\)");
+ std::string regex;
+ if(this->MemoryTesterStyle == cmCTestMemCheckHandler::THREAD_SANITIZER)
+ {
+ regex = "WARNING: ThreadSanitizer: (.*) \\(pid=.*\\)";
+ }
+ else
+ {
+ regex = "ERROR: AddressSanitizer: (.*) on.*";
+ }
+ cmsys::RegularExpression sanitizerWarning(regex);
+ cmsys::RegularExpression leakWarning("(Direct|Indirect) leak of .*");
int defects = 0;
std::vector<std::string> lines;
cmSystemTools::Split(str.c_str(), lines);
@@ -744,10 +788,18 @@ bool cmCTestMemCheckHandler::ProcessMemCheckThreadSanitizerOutput(
for( std::vector<std::string>::iterator i = lines.begin();
i != lines.end(); ++i)
{
- if(sanitizerWarning.find(*i))
+ std::string resultFound;
+ if(leakWarning.find(*i))
+ {
+ resultFound = leakWarning.match(1)+" leak";
+ }
+ else if (sanitizerWarning.find(*i))
+ {
+ resultFound = sanitizerWarning.match(1);
+ }
+ if(resultFound.size())
{
- std::string warning = sanitizerWarning.match(1);
- std::vector<int>::size_type idx = this->FindOrAddWarning(warning);
+ std::vector<int>::size_type idx = this->FindOrAddWarning(resultFound);
if(result.size() == 0 || idx > result.size()-1)
{
result.push_back(1);
diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h
index ffe57f6..2630fde 100644
--- a/Source/CTest/cmCTestMemCheckHandler.h
+++ b/Source/CTest/cmCTestMemCheckHandler.h
@@ -50,7 +50,8 @@ private:
PURIFY,
BOUNDS_CHECKER,
// checkers after hear do not use the standard error list
- THREAD_SANITIZER
+ THREAD_SANITIZER,
+ ADDRESS_SANITIZER
};
public:
enum { // Memory faults
@@ -132,9 +133,9 @@ private:
bool ProcessMemCheckPurifyOutput(const std::string& str,
std::string& log,
std::vector<int>& results);
- bool ProcessMemCheckThreadSanitizerOutput(const std::string& str,
- std::string& log,
- std::vector<int>& results);
+ bool ProcessMemCheckSanitizerOutput(const std::string& str,
+ std::string& log,
+ std::vector<int>& results);
bool ProcessMemCheckBoundsCheckerOutput(const std::string& str,
std::string& log,
std::vector<int>& results);
diff --git a/Source/cmXMLParser.cxx b/Source/cmXMLParser.cxx
index a73fd70..391b874 100644
--- a/Source/cmXMLParser.cxx
+++ b/Source/cmXMLParser.cxx
@@ -20,6 +20,8 @@ cmXMLParser::cmXMLParser()
{
this->Parser = 0;
this->ParseError = 0;
+ this->ReportCallback = 0;
+ this->ReportCallbackData = 0;
}
//----------------------------------------------------------------------------
@@ -233,6 +235,13 @@ void cmXMLParser::ReportXmlParseError()
//----------------------------------------------------------------------------
void cmXMLParser::ReportError(int line, int, const char* msg)
{
- std::cerr << "Error parsing XML in stream at line "
- << line << ": " << msg << std::endl;
+ if(this->ReportCallback)
+ {
+ this->ReportCallback(line, msg, this->ReportCallbackData);
+ }
+ else
+ {
+ std::cerr << "Error parsing XML in stream at line "
+ << line << ": " << msg << std::endl;
+ }
}
diff --git a/Source/cmXMLParser.h b/Source/cmXMLParser.h
index 84a5a7d..e72da66 100644
--- a/Source/cmXMLParser.h
+++ b/Source/cmXMLParser.h
@@ -50,11 +50,18 @@ public:
virtual int ParseChunk(const char* inputString,
std::string::size_type length);
virtual int CleanupParser();
-
+ typedef void (*ReportFunction)(int, const char*, void*);
+ void SetErrorCallback(ReportFunction f, void* d)
+ {
+ this->ReportCallback = f;
+ this->ReportCallbackData = d;
+ }
protected:
//! This variable is true if there was a parse error while parsing in
//chunks.
int ParseError;
+ ReportFunction ReportCallback;
+ void* ReportCallbackData;
//1 Expat parser structure. Exists only during call to Parse().
void* Parser;