Jelajahi Sumber

Merge topic 'ctest_memcheck-leak_sanitizer'

e537bd91 ctest_memcheck: do not add detect_leaks=1 to ASAN_OPTIONS
0a2e5885 ctest_memcheck: join *SAN_OPTIONS with :
cdacfbd2 MEMORYCHECK_SUPPRESSIONS_FILE: add support for sanitizers
cf590c12 ctest_memcheck: add support for standalone LeakSanitizer
Brad King 8 tahun lalu
induk
melakukan
12d5ccd10a

+ 19 - 0
Help/release/dev/ctest_memcheck-leak_sanitizer.rst

@@ -0,0 +1,19 @@
+ctest_memcheck-leak_sanitizer
+=============================
+
+* The :command:`ctest_memcheck` command learned to support ``LeakSanitizer``
+  independently from ``AddressSanitizer``.
+
+* The :command:`ctest_memcheck` command no longer automatically adds
+  ``leak_check=1`` to the options used by ``AddressSanitizer``. The default
+  behavior of ``AddressSanitizer`` is to run `LeakSanitizer` to check leaks
+  unless ``leak_check=0``.
+
+* The :command:`ctest_memcheck` command learned to read the location of
+  suppressions files for sanitizers from the
+  :variable:`CTEST_MEMORYCHECK_SUPPRESSIONS_FILE` variable.
+
+* The :command:`ctest_memcheck` command was fixed to correctly append extra
+  sanitizer options read from the
+  :variable:`CTEST_MEMORYCHECK_SANITIZER_OPTIONS` variable to the environment
+  variables used internally by the sanitizers.

+ 1 - 1
Help/variable/CTEST_MEMORYCHECK_TYPE.rst

@@ -4,5 +4,5 @@ CTEST_MEMORYCHECK_TYPE
 Specify the CTest ``MemoryCheckType`` setting
 in a :manual:`ctest(1)` dashboard client script.
 Valid values are ``Valgrind``, ``Purify``, ``BoundsChecker``, and
-``ThreadSanitizer``, ``AddressSanitizer``, ``MemorySanitizer``, and
+``ThreadSanitizer``, ``AddressSanitizer``, ``LeakSanitizer``, ``MemorySanitizer``, and
 ``UndefinedBehaviorSanitizer``.

+ 27 - 4
Source/CTest/cmCTestMemCheckHandler.cxx

@@ -305,6 +305,9 @@ void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml)
     case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
       xml.Attribute("Checker", "AddressSanitizer");
       break;
+    case cmCTestMemCheckHandler::LEAK_SANITIZER:
+      xml.Attribute("Checker", "LeakSanitizer");
+      break;
     case cmCTestMemCheckHandler::THREAD_SANITIZER:
       xml.Attribute("Checker", "ThreadSanitizer");
       break;
@@ -458,6 +461,12 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
     this->MemoryTesterStyle = cmCTestMemCheckHandler::ADDRESS_SANITIZER;
     this->LogWithPID = true; // even if we give the log file the pid is added
   }
+  if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
+      "LeakSanitizer") {
+    this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand");
+    this->MemoryTesterStyle = cmCTestMemCheckHandler::LEAK_SANITIZER;
+    this->LogWithPID = true; // even if we give the log file the pid is added
+  }
   if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
       "ThreadSanitizer") {
     this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand");
@@ -586,6 +595,7 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
     }
     // these are almost the same but the env var used is different
     case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+    case cmCTestMemCheckHandler::LEAK_SANITIZER:
     case cmCTestMemCheckHandler::THREAD_SANITIZER:
     case cmCTestMemCheckHandler::MEMORY_SANITIZER:
     case cmCTestMemCheckHandler::UB_SANITIZER: {
@@ -597,12 +607,20 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
       this->MemoryTesterDynamicOptions.push_back("-E");
       this->MemoryTesterDynamicOptions.push_back("env");
       std::string envVar;
-      std::string extraOptions =
+      std::string extraOptions = ":" +
         this->CTest->GetCTestConfiguration("MemoryCheckSanitizerOptions");
+      std::string suppressionsOption;
+      if (!this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile")
+             .empty()) {
+        suppressionsOption = ":suppressions=" +
+          this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile");
+      }
       if (this->MemoryTesterStyle ==
           cmCTestMemCheckHandler::ADDRESS_SANITIZER) {
         envVar = "ASAN_OPTIONS";
-        extraOptions += " detect_leaks=1";
+      } else if (this->MemoryTesterStyle ==
+                 cmCTestMemCheckHandler::LEAK_SANITIZER) {
+        envVar = "LSAN_OPTIONS";
       } else if (this->MemoryTesterStyle ==
                  cmCTestMemCheckHandler::THREAD_SANITIZER) {
         envVar = "TSAN_OPTIONS";
@@ -614,8 +632,9 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking()
         envVar = "UBSAN_OPTIONS";
       }
       std::string outputFile =
-        envVar + "=log_path=\"" + this->MemoryTesterOutputFile + "\" ";
-      this->MemoryTesterEnvironmentVariable = outputFile + extraOptions;
+        envVar + "=log_path=\"" + this->MemoryTesterOutputFile + "\"";
+      this->MemoryTesterEnvironmentVariable =
+        outputFile + extraOptions + suppressionsOption;
       break;
     }
     default:
@@ -644,6 +663,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str,
     case cmCTestMemCheckHandler::PURIFY:
       return this->ProcessMemCheckPurifyOutput(str, log, results);
     case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
+    case cmCTestMemCheckHandler::LEAK_SANITIZER:
     case cmCTestMemCheckHandler::THREAD_SANITIZER:
     case cmCTestMemCheckHandler::MEMORY_SANITIZER:
     case cmCTestMemCheckHandler::UB_SANITIZER:
@@ -680,6 +700,9 @@ bool cmCTestMemCheckHandler::ProcessMemCheckSanitizerOutput(
     case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
       regex = "ERROR: AddressSanitizer: (.*) on.*";
       break;
+    case cmCTestMemCheckHandler::LEAK_SANITIZER:
+      // use leakWarning regex
+      break;
     case cmCTestMemCheckHandler::THREAD_SANITIZER:
       regex = "WARNING: ThreadSanitizer: (.*) \\(pid=.*\\)";
       break;

+ 1 - 0
Source/CTest/cmCTestMemCheckHandler.h

@@ -47,6 +47,7 @@ private:
     BOUNDS_CHECKER,
     // checkers after here do not use the standard error list
     ADDRESS_SANITIZER,
+    LEAK_SANITIZER,
     THREAD_SANITIZER,
     MEMORY_SANITIZER,
     UB_SANITIZER

+ 1 - 0
Tests/RunCMake/ctest_memcheck/DummyAddressLeakSanitizer-result.txt

@@ -0,0 +1 @@
+(-1|255)

+ 1 - 0
Tests/RunCMake/ctest_memcheck/DummyAddressLeakSanitizer-stderr.txt

@@ -0,0 +1 @@
+Cannot find memory tester output file: .*/Tests/RunCMake/ctest_memcheck/DummyAddressLeakSanitizer-build/Testing/Temporary/MemoryChecker.1.log\.\*

+ 3 - 0
Tests/RunCMake/ctest_memcheck/DummyAddressLeakSanitizer-stdout.txt

@@ -0,0 +1,3 @@
+Memory checking results:
+Direct leak - 2
+Indirect leak - 1

+ 20 - 7
Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake

@@ -30,22 +30,22 @@ unset(CMAKELISTS_EXTRA_CODE)
 unset(CTEST_EXTRA_CODE)
 
 #-----------------------------------------------------------------------------
-# add LeakSanitizer test
+# add standalone LeakSanitizer test
 set(CTEST_EXTRA_CODE
-"set(CTEST_MEMORYCHECK_SANITIZER_OPTIONS \"simulate_sanitizer=1 report_bugs=1 history_size=5 exitcode=55\")
+"set(CTEST_MEMORYCHECK_SANITIZER_OPTIONS \"simulate_sanitizer=1:report_bugs=1:history_size=5:exitcode=55\")
 ")
 set(CMAKELISTS_EXTRA_CODE
 "add_test(NAME TestSan COMMAND \"${CMAKE_COMMAND}\"
 -P \"${RunCMake_SOURCE_DIR}/testLeakSanitizer.cmake\")
 ")
-run_mc_test(DummyLeakSanitizer "" -DMEMCHECK_TYPE=AddressSanitizer)
+run_mc_test(DummyLeakSanitizer "" -DMEMCHECK_TYPE=LeakSanitizer)
 unset(CMAKELISTS_EXTRA_CODE)
 unset(CTEST_EXTRA_CODE)
 
 #-----------------------------------------------------------------------------
 # add AddressSanitizer test
 set(CTEST_EXTRA_CODE
-"set(CTEST_MEMORYCHECK_SANITIZER_OPTIONS \"simulate_sanitizer=1 report_bugs=1 history_size=5 exitcode=55\")
+"set(CTEST_MEMORYCHECK_SANITIZER_OPTIONS \"simulate_sanitizer=1:report_bugs=1:history_size=5:exitcode=55\")
 ")
 set(CMAKELISTS_EXTRA_CODE
 "add_test(NAME TestSan COMMAND \"\${CMAKE_COMMAND}\"
@@ -55,10 +55,23 @@ run_mc_test(DummyAddressSanitizer "" -DMEMCHECK_TYPE=AddressSanitizer)
 unset(CMAKELISTS_EXTRA_CODE)
 unset(CTEST_EXTRA_CODE)
 
+#-----------------------------------------------------------------------------
+# add AddressSanitizer/LeakSanitizer test
+set(CTEST_EXTRA_CODE
+"set(CTEST_MEMORYCHECK_SANITIZER_OPTIONS \"simulate_sanitizer=1:report_bugs=1:history_size=5:exitcode=55\")
+")
+set(CMAKELISTS_EXTRA_CODE
+"add_test(NAME TestSan COMMAND \"${CMAKE_COMMAND}\"
+-P \"${RunCMake_SOURCE_DIR}/testAddressLeakSanitizer.cmake\")
+")
+run_mc_test(DummyAddressLeakSanitizer "" -DMEMCHECK_TYPE=AddressSanitizer)
+unset(CMAKELISTS_EXTRA_CODE)
+unset(CTEST_EXTRA_CODE)
+
 #-----------------------------------------------------------------------------
 # add MemorySanitizer test
 set(CTEST_EXTRA_CODE
-"set(CTEST_MEMORYCHECK_COMMAND_OPTIONS \"simulate_sanitizer=1 report_bugs=1 history_size=5 exitcode=55\")
+"set(CTEST_MEMORYCHECK_COMMAND_OPTIONS \"simulate_sanitizer=1:report_bugs=1:history_size=5:exitcode=55\")
 ")
 set(CMAKELISTS_EXTRA_CODE
 "add_test(NAME TestSan COMMAND \"\${CMAKE_COMMAND}\"
@@ -151,13 +164,13 @@ unset(CTEST_SUFFIX_CODE)
 set(CTEST_SUFFIX_CODE "message(\"Defect count: \${defect_count}\")")
 set(CTEST_MEMCHECK_ARGS "DEFECT_COUNT defect_count")
 set(CTEST_EXTRA_CODE
-"set(CTEST_MEMORYCHECK_SANITIZER_OPTIONS \"simulate_sanitizer=1 report_bugs=1 history_size=5 exitcode=55\")
+"set(CTEST_MEMORYCHECK_SANITIZER_OPTIONS \"simulate_sanitizer=1:report_bugs=1:history_size=5:exitcode=55\")
 ")
 set(CMAKELISTS_EXTRA_CODE
 "add_test(NAME TestSan COMMAND \"${CMAKE_COMMAND}\"
 -P \"${RunCMake_SOURCE_DIR}/testLeakSanitizer.cmake\")
 ")
-run_mc_test(DummyLeakSanitizerPrintDefects "" -DMEMCHECK_TYPE=AddressSanitizer)
+run_mc_test(DummyLeakSanitizerPrintDefects "" -DMEMCHECK_TYPE=LeakSanitizer)
 unset(CMAKELISTS_EXTRA_CODE)
 unset(CTEST_EXTRA_CODE)
 unset(CTEST_MEMCHECK_ARGS)

+ 47 - 0
Tests/RunCMake/ctest_memcheck/testAddressLeakSanitizer.cmake

@@ -0,0 +1,47 @@
+# this file simulates a program that has been built with AddressSanitizer
+# options
+
+message("ASAN_OPTIONS = [$ENV{ASAN_OPTIONS}]")
+string(REGEX REPLACE ".*log_path=\"([^\"]*)\".*" "\\1" LOG_FILE "$ENV{ASAN_OPTIONS}")
+message("LOG_FILE=[${LOG_FILE}]")
+
+# if we are not asked to simulate AddressSanitizer don't do it
+if(NOT "$ENV{ASAN_OPTIONS}]" MATCHES "simulate_sanitizer.1")
+  return()
+endif()
+
+# clear the log files
+file(REMOVE "${LOG_FILE}.2343")
+file(REMOVE "${LOG_FILE}.2344")
+
+# create an error of each type of LeakSanitizer
+
+file(APPEND "${LOG_FILE}.2343"
+"=================================================================
+==25308==ERROR: LeakSanitizer: detected memory leaks
+
+Direct leak of 4360 byte(s) in 1 object(s) allocated from:
+    #0 0x46c669 in operator new[](unsigned long) (/home/kitware/msan/a.out+0x46c669)
+    #1 0x4823b4 in main /home/kitware/msan/memcheck.cxx:12
+    #2 0x7fa72bee476c in __libc_start_main /build/buildd/eglibc-2.15/csu/libc-start.c:226
+
+SUMMARY: AddressSanitizer: 4436 byte(s) leaked in 2 allocation(s).
+")
+file(APPEND "${LOG_FILE}.2342"
+"=================================================================
+==25308==ERROR: LeakSanitizer: detected memory leaks
+
+Direct leak of 76 byte(s) in 1 object(s) allocated from:
+    #0 0x46c669 in operator new[](unsigned long) (/home/kitware/msan/a.out+0x46c669)
+    #1 0x4821b8 in foo() /home/kitware/msan/memcheck.cxx:4
+    #2 0x4823f2 in main /home/kitware/msan/memcheck.cxx:14
+    #3 0x7fa72bee476c in __libc_start_main /build/buildd/eglibc-2.15/csu/libc-start.c:226
+
+Indirect leak of 76 byte(s) in 1 object(s) allocated from:
+    #0 0x46c669 in operator new[](unsigned long) (/home/kitware/msan/a.out+0x46c669)
+    #1 0x4821b8 in foo() /home/kitware/msan/memcheck.cxx:4
+    #2 0x4823f2 in main /home/kitware/msan/memcheck.cxx:14
+    #3 0x7fa72bee476c in __libc_start_main /build/buildd/eglibc-2.15/csu/libc-start.c:226
+
+SUMMARY: AddressSanitizer: 4436 byte(s) leaked in 2 allocation(s).
+")

+ 10 - 10
Tests/RunCMake/ctest_memcheck/testLeakSanitizer.cmake

@@ -1,20 +1,20 @@
-# this file simulates a program that has been built with thread sanitizer
+# this file simulates a program that has been built with LeakSanitizer
 # options
 
-message("ASAN_OPTIONS = [$ENV{ASAN_OPTIONS}]")
-string(REGEX REPLACE ".*log_path=\"([^\"]*)\".*" "\\1" LOG_FILE "$ENV{ASAN_OPTIONS}")
+message("LSAN_OPTIONS = [$ENV{LSAN_OPTIONS}]")
+string(REGEX REPLACE ".*log_path=\"([^\"]*)\".*" "\\1" LOG_FILE "$ENV{LSAN_OPTIONS}")
 message("LOG_FILE=[${LOG_FILE}]")
-# if we are not asked to simulate leak sanitizer don't do it
-if(NOT "$ENV{ASAN_OPTIONS}]" MATCHES "simulate_sanitizer.1")
+
+# if we are not asked to simulate LeakSanitizer don't do it
+if(NOT "$ENV{LSAN_OPTIONS}]" MATCHES "simulate_sanitizer.1")
   return()
 endif()
 
-# clear the log file
+# clear the log files
 file(REMOVE "${LOG_FILE}.2343")
 file(REMOVE "${LOG_FILE}.2344")
 
-# create an error of each type of thread santizer
-# these names come from tsan_report.cc in llvm
+# create an error of each type of LeakSanitizer
 
 file(APPEND "${LOG_FILE}.2343"
 "=================================================================
@@ -25,7 +25,7 @@ Direct leak of 4360 byte(s) in 1 object(s) allocated from:
     #1 0x4823b4 in main /home/kitware/msan/memcheck.cxx:12
     #2 0x7fa72bee476c in __libc_start_main /build/buildd/eglibc-2.15/csu/libc-start.c:226
 
-SUMMARY: AddressSanitizer: 4436 byte(s) leaked in 2 allocation(s).
+SUMMARY: LeakSanitizer: 4436 byte(s) leaked in 2 allocation(s).
 ")
 file(APPEND "${LOG_FILE}.2342"
 "=================================================================
@@ -43,5 +43,5 @@ Indirect leak of 76 byte(s) in 1 object(s) allocated from:
     #2 0x4823f2 in main /home/kitware/msan/memcheck.cxx:14
     #3 0x7fa72bee476c in __libc_start_main /build/buildd/eglibc-2.15/csu/libc-start.c:226
 
-SUMMARY: AddressSanitizer: 4436 byte(s) leaked in 2 allocation(s).
+SUMMARY: LeakSanitizer: 4436 byte(s) leaked in 2 allocation(s).
 ")