From 2732bfde8c80656b1f95df212e6becdf402b89f4 Mon Sep 17 00:00:00 2001 From: PastaClaw Date: Fri, 3 Jul 2026 11:12:23 -0500 Subject: [PATCH] test: fix data race on captured log lines in llmq commitment test commitment_check_undersized_bitset_debug_log_test scanned its log_lines vector while its PushBackCallback was still registered. Logger callbacks run under the logger mutex from whichever thread logs, and RegTestingSetup keeps background threads (scheduler, LLMQ) alive that log concurrently, so a push_back could reallocate the vector mid-scan and invalidate the main thread's iterators, segfaulting the linux64_multiprocess unit-test job. Hold the RAII capture guard in a std::optional and reset() it after CheckLLMQCommitment returns but before reading log_lines. DeleteCallback takes the same logger mutex as callback dispatch, so once reset() returns no thread can still be mutating the vector. Exception paths keep the existing guard-destructor cleanup. Co-Authored-By: Claude Fable 5 --- src/test/llmq_commitment_tests.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/llmq_commitment_tests.cpp b/src/test/llmq_commitment_tests.cpp index cb7fe1530004..d9bebee9cb87 100644 --- a/src/test/llmq_commitment_tests.cpp +++ b/src/test/llmq_commitment_tests.cpp @@ -21,6 +21,7 @@ #include #include +#include using namespace llmq; using namespace llmq::testutils; @@ -124,7 +125,7 @@ BOOST_FIXTURE_TEST_CASE(commitment_check_undersized_bitset_debug_log_test, RegTe }; std::vector log_lines; - LogCaptureGuard guard{log_lines}; + std::optional guard{std::in_place, log_lines}; BOOST_REQUIRE(LogAcceptDebug(BCLog::LLMQ)); CFinalCommitmentTxPayload payload; @@ -168,6 +169,12 @@ BOOST_FIXTURE_TEST_CASE(commitment_check_undersized_bitset_debug_log_test, RegTe BOOST_CHECK(state.IsInvalid()); BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-qc-height"); + // Remove the callback before reading log_lines: callbacks run under the + // logger mutex from whichever thread logs, and RegTestingSetup has + // background threads that log concurrently. DeleteCallback takes the same + // mutex, so after this reset no thread can still be mutating log_lines. + guard.reset(); + // Locate the validMembers debug line emitted by CheckLLMQCommitment and // assert the loop was clamped: with an empty bitset the rendered list must // be empty. Old code emitted "v[0]=..." here even though the bitset had no