diff options
author | Bill Hoffman <bill.hoffman@kitware.com> | 2014-07-14 21:01:47 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2014-07-16 15:50:23 (GMT) |
commit | 44726714322ca0b75628e234229f4583a480d7ec (patch) | |
tree | 5e5ffa1fb65bec92047096f68f0d7defe5be1108 /Source | |
parent | 49bf3e7d8daab2a1e7ba435d011618bd2c516766 (diff) | |
download | CMake-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.cxx | 74 | ||||
-rw-r--r-- | Source/CTest/cmCTestMemCheckHandler.h | 9 | ||||
-rw-r--r-- | Source/cmXMLParser.cxx | 13 | ||||
-rw-r--r-- | Source/cmXMLParser.h | 9 |
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; |