From: Kefu Chai Date: Sat, 25 Apr 2026 03:54:16 +0000 (+0800) Subject: ceph-dencoder: skip dlclose under ASan so leaks symbolise X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=05a28d1b635ca3d7e047545eec986b9bdade5a72;p=ceph.git ceph-dencoder: skip dlclose under ASan so leaks symbolise The DencoderPlugin destructor calls dlclose() on each loaded plugin .so before main() returns. When LeakSanitizer's atexit-registered leak check then runs, the plugin .so is no longer mapped in the process address space, and any leak whose allocation stack passes through plugin code is reported with "" — useless for investigation. This is not an ASan bug or a missing -g flag; it is the unavoidable ordering of dlclose-before-leak-check. Skipping dlclose under __SANITIZE_ADDRESS__ leaves the plugins mapped until process exit, restoring symbolisation. The functional cost is zero: the kernel will unmap the .so segments when the process exits anyway. Without this, a developer triaging dencoder leaks under ASan has no visibility into which plugin or which static initialiser is responsible. With this, the leak stacks resolve to real symbols and real bugs become triagable. This commit does not change leak-detection results in non-sanitiser builds and is a no-op on FreeBSD (which already skipped dlclose). Signed-off-by: Kefu Chai --- diff --git a/src/tools/ceph-dencoder/denc_plugin.h b/src/tools/ceph-dencoder/denc_plugin.h index c5eacce47cb4..09cb1438f17c 100644 --- a/src/tools/ceph-dencoder/denc_plugin.h +++ b/src/tools/ceph-dencoder/denc_plugin.h @@ -24,11 +24,23 @@ public: } ~DencoderPlugin() { unregister_dencoders(); -#if !defined(__FreeBSD__) +#if defined(__has_feature) +# if __has_feature(address_sanitizer) || __has_feature(leak_sanitizer) +# define DENC_SKIP_DLCLOSE 1 +# endif +#endif +#if defined(__SANITIZE_ADDRESS__) && !defined(DENC_SKIP_DLCLOSE) +# define DENC_SKIP_DLCLOSE 1 +#endif +#if !defined(__FreeBSD__) && !defined(DENC_SKIP_DLCLOSE) + // Skip dlclose under ASan/LSan: the leak checker at process exit needs + // the .so still mapped to resolve symbols. Clang may not define + // __SANITIZE_ADDRESS__ (e.g. clang-19), hence the __has_feature check. if (mod) { dlclose(mod); } #endif +#undef DENC_SKIP_DLCLOSE } const dencoders_t& register_dencoders() { static constexpr std::string_view REGISTER_DENCODERS_FUNCTION = "register_dencoders\0";