From 7b43dd4504e1a3764cda2cca23ab77fa0f50b9b9 Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Wed, 10 Jun 2026 13:44:38 -0500 Subject: [PATCH 1/2] fix: guard HAVE_MAT_LIVEEVENTINSPECTOR/PRIVACYGUARD against redefinition Under -Werror on Linux/macOS, the modules-repo CI (build-posix-latest-exp) has been failing for ~2 weeks with: config-default.h:36: error: 'HAVE_MAT_LIVEEVENTINSPECTOR' macro redefined [-Werror,-Wmacro-redefined] config-default.h:37: error: 'HAVE_MAT_PRIVACYGUARD' macro redefined tests/functests/CMakeLists.txt and tests/unittests/CMakeLists.txt add -DHAVE_MAT_LIVEEVENTINSPECTOR / -DHAVE_MAT_PRIVACYGUARD on the command line when BUILD_LIVEEVENTINSPECTOR / BUILD_PRIVACYGUARD (default YES) and the respective module dir exists. The three config-default headers then redefined them unconditionally, which is fatal under -Werror (added by #1415). Wrapping the two defines in #ifndef in all three config-default*.h headers preserves all existing behavior: - Without command-line -D: macros get defined here as before. - With command-line -D: header skips the redefinition, no warning. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lib/include/mat/config-default-cs4.h | 8 ++++++++ lib/include/mat/config-default-exp.h | 8 ++++++++ lib/include/mat/config-default.h | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/lib/include/mat/config-default-cs4.h b/lib/include/mat/config-default-cs4.h index 7aae9fc7e..71a79c10f 100644 --- a/lib/include/mat/config-default-cs4.h +++ b/lib/include/mat/config-default-cs4.h @@ -27,8 +27,16 @@ /* #define HAVE_MAT_EVT_TRACEID */ #define HAVE_MAT_STORAGE #define HAVE_MAT_DEFAULT_HTTP_CLIENT +// The two macros below are also added on the command line by +// tests/{functests,unittests}/CMakeLists.txt when BUILD_LIVEEVENTINSPECTOR +// / BUILD_PRIVACYGUARD are ON. Guard against -Wmacro-redefined under +// -Werror on Linux/macOS. +#ifndef HAVE_MAT_LIVEEVENTINSPECTOR #define HAVE_MAT_LIVEEVENTINSPECTOR +#endif +#ifndef HAVE_MAT_PRIVACYGUARD #define HAVE_MAT_PRIVACYGUARD +#endif //#define HAVE_MAT_DEFAULT_FILTER #if defined(_WIN32) && !defined(_WINRT_DLL) #define HAVE_MAT_NETDETECT diff --git a/lib/include/mat/config-default-exp.h b/lib/include/mat/config-default-exp.h index 609692a01..256dfe615 100644 --- a/lib/include/mat/config-default-exp.h +++ b/lib/include/mat/config-default-exp.h @@ -25,8 +25,16 @@ /* #define HAVE_MAT_EVT_TRACEID */ #define HAVE_MAT_STORAGE #define HAVE_MAT_DEFAULT_HTTP_CLIENT +// The two macros below are also added on the command line by +// tests/{functests,unittests}/CMakeLists.txt when BUILD_LIVEEVENTINSPECTOR +// / BUILD_PRIVACYGUARD are ON. Guard against -Wmacro-redefined under +// -Werror on Linux/macOS. +#ifndef HAVE_MAT_LIVEEVENTINSPECTOR #define HAVE_MAT_LIVEEVENTINSPECTOR +#endif +#ifndef HAVE_MAT_PRIVACYGUARD #define HAVE_MAT_PRIVACYGUARD +#endif //#define HAVE_MAT_DEFAULT_FILTER #if defined(_WIN32) && !defined(_WINRT_DLL) #define HAVE_MAT_NETDETECT diff --git a/lib/include/mat/config-default.h b/lib/include/mat/config-default.h index 9617611c9..2ddce7dfc 100644 --- a/lib/include/mat/config-default.h +++ b/lib/include/mat/config-default.h @@ -33,8 +33,16 @@ /* #define HAVE_MAT_EVT_TRACEID */ #define HAVE_MAT_STORAGE #define HAVE_MAT_DEFAULT_HTTP_CLIENT +// The two macros below are also added on the command line by +// tests/{functests,unittests}/CMakeLists.txt when BUILD_LIVEEVENTINSPECTOR +// / BUILD_PRIVACYGUARD are ON. Guard against -Wmacro-redefined under +// -Werror on Linux/macOS. +#ifndef HAVE_MAT_LIVEEVENTINSPECTOR #define HAVE_MAT_LIVEEVENTINSPECTOR +#endif +#ifndef HAVE_MAT_PRIVACYGUARD #define HAVE_MAT_PRIVACYGUARD +#endif //#define HAVE_MAT_DEFAULT_FILTER #if defined(_WIN32) && !defined(_WINRT_DLL) #define HAVE_MAT_NETDETECT From fc7375aaf2a28566ea0fd1c59e2f67a3f314ba4d Mon Sep 17 00:00:00 2001 From: Bhagirath Mehta Date: Thu, 11 Jun 2026 03:16:33 -0500 Subject: [PATCH 2/2] fix: prevent EDEADLK self-join in ~CurlHttpOperation on async-thread destruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The modules-repo CI test ECSClientFuncTests.GetConfigs (and every test in the ECSClientFuncTests suite) crashed on Linux/macOS with: terminate called after throwing an instance of 'std::system_error' what(): Resource deadlock avoided Aborted (core dumped) Root cause ========== SendAsync() runs Send() + the user callback on a std::async worker thread. The callback owns a strong ref to CurlHttpOperation, so when it releases the last ref the ~CurlHttpOperation destructor runs on the async thread itself. libstdc++'s std::future<>::~future implicitly calls _Async_state_impl::~_Async_state_impl, which calls _M_complete_async -> _M_join via std::call_once. On the async thread that's a self-join; call_once throws std::system_error(EDEADLK). Because the throw escapes a noexcept destructor, terminate() aborts the process. A try/catch around the future cannot rescue this — destructors of std::future are noexcept. Fix === Move the future onto a detached helper thread before its destructor runs. The helper is by definition NOT the async thread (we'd only be on the async thread if its work already finished), so the implicit join completes immediately. On the common path (destruction from the caller thread) it costs one short-lived thread spawn that exits in microseconds. Verified locally with sister + modules linked: all 113 FuncTests pass, including all 25 ECSClientFuncTests (which include the formerly-fatal GetConfigs). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lib/http/HttpClient_Curl.hpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/http/HttpClient_Curl.hpp b/lib/http/HttpClient_Curl.hpp index 972cc4fec..012a2fd99 100644 --- a/lib/http/HttpClient_Curl.hpp +++ b/lib/http/HttpClient_Curl.hpp @@ -169,11 +169,26 @@ class CurlHttpOperation { */ virtual ~CurlHttpOperation() { - // Given the request has not been aborted we should wait for completion here - // This guarantees the lifetime of this request. + // libstdc++'s std::future<>::~future implicitly joins the async + // thread via call_once during destruction. If this destructor runs + // ON that same async thread (e.g. the user callback released the + // last shared_ptr from inside the lambda), the implicit self-join + // throws std::system_error("Resource deadlock avoided"), and because + // the throw originates inside a noexcept destructor it aborts the + // process. try/catch around `result` cannot rescue it. + // + // Defuse by moving the future onto a detached helper thread that is + // by definition NOT the async thread, so its implicit join succeeds + // immediately (the work has already finished, which is the only way + // we could be running this destructor on the async thread). On the + // common path (destructed from the caller thread) this just spawns + // a no-op helper that exits in microseconds. if (result.valid()) { - result.wait(); + std::thread([f = std::move(result)]() mutable { + // f goes out of scope here. ~future joins on this new + // thread (!= the original async thread), so no EDEADLK. + }).detach(); } DispatchEvent(OnDestroy); res = CURLE_OK;