From 5ae00a3dabe0d5d3684c2b5bf05c9ad51ff27fef Mon Sep 17 00:00:00 2001 From: Nikos Dragazis Date: Mon, 30 Jun 2025 17:55:27 +0300 Subject: [PATCH] test: kmip: Fix segfault from premature destruction of port_promise `kmip_test_helper()` is a utility function to spawn a dedicated PyKMIP server for a particular Boost test case. The function runs the server as an external process and uses a thread to parse the port from the server's logs. The thread communicates the port to the main thread via a promise. The current implementation has a bug where the thread may set a value to the promise after its destruction, causing a segfault. This happens when the server does not start within 20 seconds, in which case the port future throws and the stack unwinding machinery destroys the port promise before the thread that writes to it. Fix the bug by declaring the promise before the cleanup action. The bug has been encountered in CI runs on slow machines, where the PyKMIP server takes too long to create its internal tables (due to slow fdatasync calls from SQLite). This patch does not improve CI stability - it only ensures that the error condition is properly reflected in the test output. This patch is not a backport. The same bug has been fixed in master as part of a larger rewrite of the `kmip_test_helper()` (see 722e2bce96). Refs #24747, #24842. Fixes #24574. Signed-off-by: Nikos Dragazis Closes scylladb/scylladb#25029 --- test/boost/encryption_at_rest_test.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/boost/encryption_at_rest_test.cc b/test/boost/encryption_at_rest_test.cc index 3ac78660aa..4e57d4a842 100644 --- a/test/boost/encryption_at_rest_test.cc +++ b/test/boost/encryption_at_rest_test.cc @@ -305,6 +305,9 @@ static future<> kmip_test_helper(const std::function(const kmip_test_in std::future pykmip_status; + std::promise port_promise; + auto fut = port_promise.get_future(); + static const char* def_resourcedir = "./test/resource/certs"; const char* resourcedir = std::getenv("KMIP_RESOURCE_DIR"); if (resourcedir == nullptr) { @@ -368,9 +371,6 @@ database_path=:memory: bp::env["TMPDIR"]=tmp.path().string() ); - std::promise port_promise; - auto f = port_promise.get_future(); - pykmip_status = std::async([&] { static std::regex port_ex("Listening on (\\d+)"); @@ -393,10 +393,10 @@ database_path=:memory: } }); // arbitrary timeout of 20s for the server to make some output. Very generous. - if (f.wait_for(20s) == std::future_status::timeout) { + if (fut.wait_for(20s) == std::future_status::timeout) { throw std::runtime_error("Could not start pykmip"); } - auto port = f.get(); + auto port = fut.get(); if (port <= 0) { throw std::runtime_error("Invalid port"); }