]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Detect memory leaks during regression tests in CI
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 2 May 2024 15:16:10 +0000 (17:16 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 7 May 2024 07:12:58 +0000 (09:12 +0200)
.github/workflows/build-and-test-all.yml
m4/pdns_enable_sanitizers.m4
pdns/dnsdistdist/dnsdist-lsan.supp [new file with mode: 0644]
pdns/dnsdistdist/dnsdist.cc
regression-tests.dnsdist/dnsdisttests.py

index c30fb4a06a2fd853d391cf8723cd83c4476ebba0..b686ed4b291aa24fb23a416adc74316592c3f01b 100644 (file)
@@ -656,6 +656,7 @@ jobs:
         UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1:suppressions=${{ env.REPO_HOME }}/build-scripts/UBSan.supp"
         # Disabling (intercept_send=0) the custom send wrappers for ASAN and TSAN because they cause the tools to report a race that doesn't exist on actual implementations of send(), see https://github.com/google/sanitizers/issues/1498
         ASAN_OPTIONS: intercept_send=0
+        LSAN_OPTIONS: "suppressions=${{ env.REPO_HOME }}/pdns/dnsdistdist/dnsdist-lsan.supp"
         TSAN_OPTIONS: "halt_on_error=1:intercept_send=0:suppressions=${{ env.REPO_HOME }}/pdns/dnsdistdist/dnsdist-tsan.supp"
         # IncludeDir tests are disabled because of a weird interaction between TSAN and these tests which ever only happens on GH actions
         SKIP_INCLUDEDIR_TESTS: yes
index 6773e1a9911319d1eed0f9bf3a1bb264e785c73a..6243dce06bb230d307c8bd6d931b910e9902f458 100644 (file)
@@ -78,6 +78,10 @@ AC_DEFUN([PDNS_ENABLE_ASAN], [
             [#include <sanitizer/common_interface_defs.h>]
           )]
         )
+        AC_CHECK_HEADERS([sanitizer/lsan_interface.h],
+          AC_DEFINE([HAVE_LEAK_SANITIZER_INTERFACE], [1], [Define if LSAN interface is available.]),
+         []
+        )
       ],
       [AC_MSG_ERROR([Cannot enable AddressSanitizer])]
     )
@@ -121,6 +125,10 @@ AC_DEFUN([PDNS_ENABLE_LSAN], [
       [SANITIZER_FLAGS="-fsanitize=leak $SANITIZER_FLAGS"],
       [AC_MSG_ERROR([Cannot enable LeakSanitizer])]
     )
+    AC_CHECK_HEADERS([sanitizer/lsan_interface.h],
+      AC_DEFINE([HAVE_LEAK_SANITIZER_INTERFACE], [1], [Define if LSAN interface is available.]),
+      []
+    )
   ])
   AC_SUBST([SANITIZER_FLAGS])
 ])
@@ -164,4 +172,3 @@ AC_DEFUN([PDNS_ENABLE_MSAN], [
   ])
   AC_SUBST([SANITIZER_FLAGS])
 ])
-
diff --git a/pdns/dnsdistdist/dnsdist-lsan.supp b/pdns/dnsdistdist/dnsdist-lsan.supp
new file mode 100644 (file)
index 0000000..a04f712
--- /dev/null
@@ -0,0 +1,2 @@
+# h2o
+leak:create_socket
index 80ee94299d8a56e91b833183981e428c3111bce6..1911e34180ff9d286d8a23aaeebf377ba5fe2c1c 100644 (file)
@@ -2753,7 +2753,22 @@ static void usage()
   cout << "-V,--version          Show dnsdist version information and exit\n";
 }
 
-#ifdef COVERAGE
+/* g++ defines __SANITIZE_THREAD__
+   clang++ supports the nice __has_feature(thread_sanitizer),
+   let's merge them */
+#if defined(__has_feature)
+#if __has_feature(thread_sanitizer)
+#define __SANITIZE_THREAD__ 1
+#endif
+#if __has_feature(address_sanitizer)
+#define __SANITIZE_ADDRESS__ 1
+#if defined(__SANITIZE_ADDRESS__) && defined(HAVE_LEAK_SANITIZER_INTERFACE)
+#include <sanitizer/lsan_interface.h>
+#endif
+#endif
+#endif
+
+#if defined(COVERAGE) || (defined(__SANITIZE_ADDRESS__) && defined(HAVE_LEAK_SANITIZER_INTERFACE))
 static void cleanupLuaObjects()
 {
   /* when our coverage mode is enabled, we need to make sure
@@ -2770,24 +2785,16 @@ static void cleanupLuaObjects()
   clearWebHandlers();
   dnsdist::lua::hooks::clearMaintenanceHooks();
 }
+#endif /* defined(COVERAGE) || (defined(__SANITIZE_ADDRESS__) && defined(HAVE_LEAK_SANITIZER_INTERFACE)) */
 
+#if defined(COVERAGE)
 static void sigTermHandler(int)
 {
   cleanupLuaObjects();
   pdns::coverage::dumpCoverageData();
   _exit(EXIT_SUCCESS);
 }
-#else /* COVERAGE */
-
-/* g++ defines __SANITIZE_THREAD__
-   clang++ supports the nice __has_feature(thread_sanitizer),
-   let's merge them */
-#if defined(__has_feature)
-#if __has_feature(thread_sanitizer)
-#define __SANITIZE_THREAD__ 1
-#endif
-#endif
-
+#else
 static void sigTermHandler([[maybe_unused]] int sig)
 {
 #if !defined(__SANITIZE_THREAD__)
@@ -2802,7 +2809,12 @@ static void sigTermHandler([[maybe_unused]] int sig)
   }
   std::cout << "Exiting on user request" << std::endl;
 #endif /* __SANITIZE_THREAD__ */
-
+#if defined(__SANITIZE_ADDRESS__) && defined(HAVE_LEAK_SANITIZER_INTERFACE)
+  auto lock = g_lua.lock();
+  cleanupLuaObjects();
+  *lock = LuaContext();
+  __lsan_do_leak_check();
+#endif /* __SANITIZE_ADDRESS__ && HAVE_LEAK_SANITIZER_INTERFACE */
   _exit(EXIT_SUCCESS);
 }
 #endif /* COVERAGE */
index 3f53bd451a53378e6a84c36a36a40ab6aad80cc3..889d40a54fa54744588862ed544f5b2424b2660c 100644 (file)
@@ -215,6 +215,8 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
                 print("kill...", p, file=sys.stderr)
                 p.kill()
                 p.wait()
+            if p.returncode != 0:
+              raise AssertionError('Process exited with return code %d' % (p.returncode))
         except OSError as e:
             # There is a race-condition with the poll() and
             # kill() statements, when the process is dead on the