From 271c6270c28809b9dded6e03cf8478dc9af825e2 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Wed, 14 Oct 2026 10:43:49 +0200 Subject: [PATCH 1/7] DPL: run framework test through leaks on macos --- Framework/Core/CMakeLists.txt | 11 +++++++++++ Framework/Core/entitlements.plist | 8 ++++++++ 2 files changed, 19 insertions(+) create mode 100644 Framework/Core/entitlements.plist diff --git a/Framework/Core/CMakeLists.txt b/Framework/Core/CMakeLists.txt index 437dc5ee6478c..0e72483f789db 100644 --- a/Framework/Core/CMakeLists.txt +++ b/Framework/Core/CMakeLists.txt @@ -280,7 +280,18 @@ target_link_libraries(o2-test-framework-core PRIVATE O2::Catch2) get_filename_component(outdir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/../tests ABSOLUTE) set_property(TARGET o2-test-framework-core PROPERTY RUNTIME_OUTPUT_DIRECTORY ${outdir}) +if(APPLE) +add_custom_command(TARGET o2-test-framework-core POST_BUILD + COMMAND codesign --force --sign - --entitlements ${CMAKE_CURRENT_SOURCE_DIR}/entitlements.plist $ + COMMENT "Re-signing o2-test-framework-core with debugging entitlements") +# Leaks originating in third-party code (Cling JIT, FairMQ / boost::program_options) +set(O2_FRAMEWORK_CORE_LEAKS_EXCLUDES + "--exclude=llvm::orc::shared::runFinalizeActions(std::__1::vector>&)" + "--exclude=fair::mq::ProgOptions::ParseAll(int, char const* const*, bool)") +add_test(NAME framework:core COMMAND leaks --quiet ${O2_FRAMEWORK_CORE_LEAKS_EXCLUDES} --groupByType --atExit -- $ --skip-benchmarks) +else() add_test(NAME framework:core COMMAND o2-test-framework-core --skip-benchmarks) +endif() o2_add_test(AlgorithmWrapper NAME test_Framework_test_AlgorithmWrapper SOURCES test/test_AlgorithmWrapper.cxx diff --git a/Framework/Core/entitlements.plist b/Framework/Core/entitlements.plist new file mode 100644 index 0000000000000..9acd12816c913 --- /dev/null +++ b/Framework/Core/entitlements.plist @@ -0,0 +1,8 @@ + + + + + com.apple.security.get-task-allow + + + From be01fc25ce903b163a76d49da6a3d01b3d0a4e89 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Wed, 14 Oct 2026 14:20:07 +0200 Subject: [PATCH 2/7] Store service names as std::string in ServiceRegistry Meta::name was a strdup'ed char const* that was never freed. Use std::string. Co-Authored-By: Claude Opus 5.5 --- Framework/Core/include/Framework/ServiceRegistry.h | 2 +- Framework/Core/src/ServiceRegistry.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Framework/Core/include/Framework/ServiceRegistry.h b/Framework/Core/include/Framework/ServiceRegistry.h index 44b75896331c6..76a01df8de4b6 100644 --- a/Framework/Core/include/Framework/ServiceRegistry.h +++ b/Framework/Core/include/Framework/ServiceRegistry.h @@ -112,7 +112,7 @@ struct ServiceRegistry { // the service. struct Meta { ServiceKind kind = ServiceKind::Serial; - char const* name = nullptr; + std::string name; // The index in the SpecIndex specIndex{}; }; diff --git a/Framework/Core/src/ServiceRegistry.cxx b/Framework/Core/src/ServiceRegistry.cxx index 09921f6b4a7d4..f7a57b8c53406 100644 --- a/Framework/Core/src/ServiceRegistry.cxx +++ b/Framework/Core/src/ServiceRegistry.cxx @@ -94,7 +94,7 @@ void ServiceRegistry::registerService(ServiceTypeHash typeHash, void* service, S if (mServicesBooked[i + index.index].compare_exchange_strong(expected, true, std::memory_order_seq_cst)) { mServicesValue[i + index.index] = service; - mServicesMeta[i + index.index] = Meta{kind, name ? strdup(name) : nullptr, specIndex}; + mServicesMeta[i + index.index] = Meta{kind, name ? std::string(name) : std::string{""}, specIndex}; mServicesKey[i + index.index] = Key{.typeHash = typeHash, .salt = salt}; std::atomic_thread_fence(std::memory_order_release); return; From 517b4dada95e9ede39e295d4d8174e7044aea5e8 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Wed, 14 Oct 2026 14:20:17 +0200 Subject: [PATCH 3/7] Do not leak frames in TestWSHandler TestWSHandler stored strdup'ed copies of every frame and never freed them. Keep the frames in a std::vector instead. Co-Authored-By: Claude Opus 5.5 --- Framework/Core/test/test_HTTPParser.cxx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Framework/Core/test/test_HTTPParser.cxx b/Framework/Core/test/test_HTTPParser.cxx index 1b87fcf49cfd4..d0a33364628d2 100644 --- a/Framework/Core/test/test_HTTPParser.cxx +++ b/Framework/Core/test/test_HTTPParser.cxx @@ -80,12 +80,12 @@ class DPLClientParser : public HTTPParser class TestWSHandler : public WebSocketHandler { public: - std::vector mFrame; + std::vector mFrame; std::vector mSize; void frame(const char* f, size_t s) final { - mFrame.push_back(strdup(f)); - mSize.push_back(s); + mFrame.emplace_back(f, s); + mSize.emplace_back(s); } }; @@ -187,7 +187,7 @@ TEST_CASE("HTTPParser1") ; // 1 for the 0, 2 for the header decode_websocket(encoded[0].base, encoded[0].len, handler); REQUIRE(handler.mSize[0] == strlen(buffer) + 1); - REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer)); + REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); } { // WebSocket multiple frame encoding / decoding @@ -214,8 +214,8 @@ TEST_CASE("HTTPParser1") decode_websocket(multiBuffer, encoded[0].len + encoded[1].len, handler); REQUIRE(handler.mFrame.size() == 2); REQUIRE(handler.mSize.size() == 2); - REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer)); - REQUIRE(std::string(handler.mFrame[1], handler.mSize[1] - 1) == std::string(buffer2)); + REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); + REQUIRE(handler.mFrame[1].substr(0, handler.mSize[1] - 1) == std::string(buffer2)); } { // Decode a frame which is split in two. @@ -229,7 +229,7 @@ TEST_CASE("HTTPParser1") decode_websocket(encoded[0].base + encoded[0].len / 2, encoded[0].len - encoded[0].len / 2, handler); REQUIRE(handler.mFrame.size() == 1); REQUIRE(handler.mSize.size() == 1); - REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer)); + REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); } { // Decode a long frame which is split in two. @@ -243,7 +243,7 @@ TEST_CASE("HTTPParser1") decode_websocket(encoded[0].base + encoded[0].len / 2, encoded[0].len - encoded[0].len / 2, handler); REQUIRE(handler.mFrame.size() == 1); REQUIRE(handler.mSize.size() == 1); - REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer)); + REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); } { // WebSocket multiple frame encoding / decoding, long frames @@ -259,8 +259,8 @@ TEST_CASE("HTTPParser1") decode_websocket(encoded[0].base, encoded[0].len, handler); REQUIRE(handler.mFrame.size() == 2); REQUIRE(handler.mSize.size() == 2); - REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer)); - REQUIRE(std::string(handler.mFrame[1], handler.mSize[1] - 1) == std::string(buffer2)); + REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); + REQUIRE(handler.mFrame[1].substr(0, handler.mSize[1] - 1) == std::string(buffer2)); } { // Decode a long frame which is split in two, after the first byte. @@ -281,7 +281,7 @@ TEST_CASE("HTTPParser1") decode_websocket(buffer2, encoded[0].len - i, handler); REQUIRE(handler.mFrame.size() == 1); REQUIRE(handler.mSize.size() == 1); - REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer)); + REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); } } { @@ -310,7 +310,7 @@ TEST_CASE("HTTPParser1") decode_websocket(buffer3, encoded[0].len - j, handler); REQUIRE(handler.mFrame.size() == 1); REQUIRE(handler.mSize.size() == 1); - REQUIRE(std::string(handler.mFrame[0], handler.mSize[0] - 1) == std::string(buffer)); + REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); } } } From 4569fff528a3c7d6665c2e86445401fd56628a30 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Wed, 14 Oct 2026 14:20:17 +0200 Subject: [PATCH 4/7] Free encoded websocket chunks in test_HTTPParser The buffers produced by encode_websocket_frames are malloc'ed and were never released. Free them at the end of each test block. Co-Authored-By: Claude Opus 5.5 --- Framework/Core/test/test_HTTPParser.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Framework/Core/test/test_HTTPParser.cxx b/Framework/Core/test/test_HTTPParser.cxx index d0a33364628d2..1aceec1157155 100644 --- a/Framework/Core/test/test_HTTPParser.cxx +++ b/Framework/Core/test/test_HTTPParser.cxx @@ -188,6 +188,7 @@ TEST_CASE("HTTPParser1") decode_websocket(encoded[0].base, encoded[0].len, handler); REQUIRE(handler.mSize[0] == strlen(buffer) + 1); REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); + std::ranges::for_each(encoded, [](auto& buf) { free(buf.base); }); } { // WebSocket multiple frame encoding / decoding @@ -216,6 +217,7 @@ TEST_CASE("HTTPParser1") REQUIRE(handler.mSize.size() == 2); REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); REQUIRE(handler.mFrame[1].substr(0, handler.mSize[1] - 1) == std::string(buffer2)); + std::ranges::for_each(encoded, [](auto& buf) { free(buf.base); }); } { // Decode a frame which is split in two. @@ -230,6 +232,7 @@ TEST_CASE("HTTPParser1") REQUIRE(handler.mFrame.size() == 1); REQUIRE(handler.mSize.size() == 1); REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); + std::ranges::for_each(encoded, [](auto& buf) { free(buf.base); }); } { // Decode a long frame which is split in two. @@ -244,6 +247,7 @@ TEST_CASE("HTTPParser1") REQUIRE(handler.mFrame.size() == 1); REQUIRE(handler.mSize.size() == 1); REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); + std::ranges::for_each(encoded, [](auto& buf) { free(buf.base); }); } { // WebSocket multiple frame encoding / decoding, long frames @@ -261,6 +265,7 @@ TEST_CASE("HTTPParser1") REQUIRE(handler.mSize.size() == 2); REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); REQUIRE(handler.mFrame[1].substr(0, handler.mSize[1] - 1) == std::string(buffer2)); + std::ranges::for_each(encoded, [](auto& buf) { free(buf.base); }); } { // Decode a long frame which is split in two, after the first byte. @@ -283,6 +288,7 @@ TEST_CASE("HTTPParser1") REQUIRE(handler.mSize.size() == 1); REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); } + std::ranges::for_each(encoded, [](auto& buf) { free(buf.base); }); } { // Decode a long frame which is split in two, after the first byte. @@ -313,6 +319,7 @@ TEST_CASE("HTTPParser1") REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); } } + std::ranges::for_each(encoded, [](auto& buf) { free(buf.base); }); } { std::string checkRequest = From 56953ec98f88a0bc689405479a39ad5d6874b293 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Wed, 14 Oct 2026 14:20:17 +0200 Subject: [PATCH 5/7] Do not leak input buffers in test_HTTPParser Request and frame inputs were strdup'ed and never freed. Use string_view on literals, make parse_http_request take char const*, and free the malloc'ed buffers. Co-Authored-By: Claude Opus 5.5 --- Framework/Core/src/HTTPParser.cxx | 5 +- Framework/Core/src/HTTPParser.h | 2 +- Framework/Core/test/test_HTTPParser.cxx | 84 +++++++++++++------------ 3 files changed, 46 insertions(+), 45 deletions(-) diff --git a/Framework/Core/src/HTTPParser.cxx b/Framework/Core/src/HTTPParser.cxx index 63537423b2708..edf4ca281f902 100644 --- a/Framework/Core/src/HTTPParser.cxx +++ b/Framework/Core/src/HTTPParser.cxx @@ -226,14 +226,13 @@ std::string encode_websocket_handshake_reply(char const* nonce, const char* prot return fmt::format(res, protocol && protocol[0] ? fmt::format("Sec-WebSocket-Protocol: {}\r\n", protocol) : "", HTTPParserHelpers::calculateAccept(nonce)); } -void parse_http_request(char* start, size_t size, HTTPParser* parser) +void parse_http_request(char const* start, size_t size, HTTPParser* parser) { - enum HTTPState state = HTTPState::IN_START; // Too short, let's try again... if (size < 2) { parser->remaining += std::string_view(start, size); } - char* cur = start; + char* cur = (char*)start; char* next = cur; std::string_view lastToken(cur, 0); std::string_view lastKey; diff --git a/Framework/Core/src/HTTPParser.h b/Framework/Core/src/HTTPParser.h index 6e253a4076ff1..9192b7b7156e0 100644 --- a/Framework/Core/src/HTTPParser.h +++ b/Framework/Core/src/HTTPParser.h @@ -236,7 +236,7 @@ struct HTTPParserHelpers { static std::string calculateAccept(const char* nonce); }; -void parse_http_request(char* start, size_t size, HTTPParser* parser); +void parse_http_request(char const* start, size_t size, HTTPParser* parser); std::pair parse_websocket_url(const char* s); } // namespace o2::framework diff --git a/Framework/Core/test/test_HTTPParser.cxx b/Framework/Core/test/test_HTTPParser.cxx index 1aceec1157155..9bbd86212fc4b 100644 --- a/Framework/Core/test/test_HTTPParser.cxx +++ b/Framework/Core/test/test_HTTPParser.cxx @@ -39,7 +39,7 @@ class DPLParser : public HTTPParser { mHeaders[std::string(k)] = v; } - void body(char* buf, size_t s) override + void body(char* buf, size_t /*s*/) override { mBody = buf; } @@ -71,7 +71,7 @@ class DPLClientParser : public HTTPParser { mHeaders[std::string(k)] = v; } - void body(char* buf, size_t s) override + void body(char* buf, size_t /*s*/) override { mBody = buf; } @@ -92,23 +92,23 @@ class TestWSHandler : public WebSocketHandler TEST_CASE("HTTPParser1") { { - char* request = strdup( + std::string_view request = "GET / HTTP/1.1\r\n" - "x-dpl-pid: 124679842\r\n\r\nCONTROL QUIT"); + "x-dpl-pid: 124679842\r\n\r\nCONTROL QUIT"; DPLParser parser; - parse_http_request(request, strlen(request), &parser); + parse_http_request(request.data(), request.size(), &parser); REQUIRE(std::string(parser.mMethod) == std::string("GET")); REQUIRE(std::string(parser.mPath) == std::string("/")); REQUIRE(std::string(parser.mVersion) == std::string("HTTP/1.1")); REQUIRE(parser.mHeaders.size() == 1); } { - char* request = strdup( + std::string_view request = "GET / HTTP/1.1\r\n" "x-dpl-pid: 124679842\r\n" - "Somethingelse: cjnjsdnjks\r\n\r\nCONTROL QUIT"); + "Somethingelse: cjnjsdnjks\r\n\r\nCONTROL QUIT"; DPLParser parser; - parse_http_request(request, strlen(request), &parser); + parse_http_request(request.data(), request.size(), &parser); REQUIRE(std::string(parser.mMethod) == std::string("GET")); REQUIRE(std::string(parser.mPath) == std::string("/")); REQUIRE(std::string(parser.mVersion) == std::string("HTTP/1.1")); @@ -119,13 +119,13 @@ TEST_CASE("HTTPParser1") } { // handle continuations... - char* request = strdup( + std::string_view request = "GET / HTTP/1.1\r\n" "x-dpl-pid: 124679842\r\n" - "Somethingelse: cjnjsdnjks\r\n\r\nCONTROL QUIT"); - char* request2 = strdup("FOO BAR"); + "Somethingelse: cjnjsdnjks\r\n\r\nCONTROL QUIT"; + std::string_view request2 = "FOO BAR"; DPLParser parser; - parse_http_request(request, strlen(request), &parser); + parse_http_request(request.data(), request.size(), &parser); REQUIRE(std::string(parser.mMethod) == std::string("GET")); REQUIRE(std::string(parser.mPath) == std::string("/")); REQUIRE(std::string(parser.mVersion) == std::string("HTTP/1.1")); @@ -133,13 +133,13 @@ TEST_CASE("HTTPParser1") REQUIRE(parser.mHeaders["x-dpl-pid"] == "124679842"); REQUIRE(parser.mHeaders["Somethingelse"] == "cjnjsdnjks"); REQUIRE(parser.mBody == "CONTROL QUIT"); - parse_http_request(request2, strlen(request2), &parser); + parse_http_request(request2.data(), request2.size(), &parser); REQUIRE(parser.mBody == "FOO BAR"); } { // WebSocket example - char* request = strdup( + std::string_view request = "GET /chat HTTP/1.1\r\n" "Host: server.example.com\r\n" "Upgrade: websocket\r\n" @@ -147,10 +147,10 @@ TEST_CASE("HTTPParser1") "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n" "Sec-WebSocket-Protocol: chat, superchat\r\n" "Sec-WebSocket-Version: 13\r\n" - "Origin: http://example.com\r\n\r\n"); + "Origin: http://example.com\r\n\r\n"; DPLParser parser; - parse_http_request(request, strlen(request), &parser); + parse_http_request(request.data(), request.size(), &parser); REQUIRE(std::string(parser.mMethod) == std::string("GET")); REQUIRE(std::string(parser.mPath) == std::string("/chat")); REQUIRE(std::string(parser.mVersion) == std::string("HTTP/1.1")); @@ -159,16 +159,16 @@ TEST_CASE("HTTPParser1") } { // WebSocket example - char* request = strdup( + std::string_view request = "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Access-Control-Allow-Origin: \"*\"\r\n" - "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"); + "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"; DPLClientParser parser; parser.states.push_back(HTTPState::IN_START_REPLY); - parse_http_request(request, strlen(request), &parser); + parse_http_request(request.data(), request.size(), &parser); REQUIRE(std::string(parser.mReplyCode) == std::string("101")); REQUIRE(std::string(parser.mReplyMessage) == std::string("Switching Protocols")); REQUIRE(std::string(parser.mReplyVersion) == std::string("HTTP/1.1")); @@ -178,23 +178,23 @@ TEST_CASE("HTTPParser1") } { // WebSocket frame encoding / decoding - char* buffer = strdup("hello websockets!"); + std::string_view buffer = "hello websockets!"; std::vector encoded; - encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + encode_websocket_frames(encoded, buffer.data(), buffer.size() + 1, WebSocketOpCode::Binary, 0); REQUIRE(encoded.size() == 1); TestWSHandler handler; - REQUIRE(encoded[0].len == strlen(buffer) + 1 + 2); + REQUIRE(encoded[0].len == buffer.size() + 1 + 2); ; // 1 for the 0, 2 for the header decode_websocket(encoded[0].base, encoded[0].len, handler); - REQUIRE(handler.mSize[0] == strlen(buffer) + 1); + REQUIRE(handler.mSize[0] == buffer.size() + 1); REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); std::ranges::for_each(encoded, [](auto& buf) { free(buf.base); }); } { // WebSocket multiple frame encoding / decoding - char* buffer = strdup("hello websockets!"); + std::string_view buffer = "hello websockets!"; std::vector encoded; - encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + encode_websocket_frames(encoded, buffer.data(), buffer.size() + 1, WebSocketOpCode::Binary, 0); REQUIRE(encoded.size() == 1); char const* prototype = "and again."; char* buffer2 = (char*)malloc(0x20000); @@ -218,12 +218,14 @@ TEST_CASE("HTTPParser1") REQUIRE(handler.mFrame[0].substr(0, handler.mSize[0] - 1) == std::string(buffer)); REQUIRE(handler.mFrame[1].substr(0, handler.mSize[1] - 1) == std::string(buffer2)); std::ranges::for_each(encoded, [](auto& buf) { free(buf.base); }); + free(multiBuffer); + free(buffer2); } { // Decode a frame which is split in two. - char* buffer = strdup("hello websockets!1"); + std::string_view buffer = "hello websockets!1"; std::vector encoded; - encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + encode_websocket_frames(encoded, buffer.data(), buffer.size() + 1, WebSocketOpCode::Binary, 0); REQUIRE(encoded.size() == 1); TestWSHandler handler; @@ -236,9 +238,9 @@ TEST_CASE("HTTPParser1") } { // Decode a long frame which is split in two. - char* buffer = strdup("string with more than 127 characters: cdsklcmalkmc cdmslkc adslkccmkadsc adslkmc dsa ckdls cdksclknds lkndnc anslkc klsad ckl lksad clkas ccdascnkjancjnjkascsa cdascds clsad nclksad ncklsd clkadns lkc sadnlk cklsa cnaksld csad"); + std::string_view buffer = "string with more than 127 characters: cdsklcmalkmc cdmslkc adslkccmkadsc adslkmc dsa ckdls cdksclknds lkndnc anslkc klsad ckl lksad clkas ccdascnkjancjnjkascsa cdascds clsad nclksad ncklsd clkadns lkc sadnlk cklsa cnaksld csad"; std::vector encoded; - encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + encode_websocket_frames(encoded, buffer.data(), buffer.size() + 1, WebSocketOpCode::Binary, 0); REQUIRE(encoded.size() == 1); TestWSHandler handler; @@ -251,12 +253,12 @@ TEST_CASE("HTTPParser1") } { // WebSocket multiple frame encoding / decoding, long frames - char* buffer = strdup("dwqnocewnclkanklcdanslkcndklsnclkdsnckldsnclk cnldcl dsklc dslk cljdnsck sdlakcn askc sdkla cnsd c sdcn dsklncn dklsc nsdkl cklds clkds ckls dklc shello websockets!"); + std::string_view buffer = "dwqnocewnclkanklcdanslkcndklsnclkdsnckldsnclk cnldcl dsklc dslk cljdnsck sdlakcn askc sdkla cnsd c sdcn dsklncn dklsc nsdkl cklds clkds ckls dklc shello websockets!"; std::vector encoded; - encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + encode_websocket_frames(encoded, buffer.data(), buffer.size() + 1, WebSocketOpCode::Binary, 0); REQUIRE(encoded.size() == 1); - char const* buffer2 = "xsanjkcnsadjknc dsjc nsdnc dlscndsck dsc ds clds cds vnlsfl nklnjk nj nju n nio nkmnklfmdkl mkld mkl mkl mkl mlk m lkm klfdnkln jkafdnk nk mkldfm lkdamlkdmlkdmlk m klml km lkm kl."; - encode_websocket_frames(encoded, buffer2, strlen(buffer2) + 1, WebSocketOpCode::Binary, 0); + std::string_view buffer2 = "xsanjkcnsadjknc dsjc nsdnc dlscndsck dsc ds clds cds vnlsfl nklnjk nj nju n nio nkmnklfmdkl mkld mkl mkl mkl mlk m lkm klfdnkln jkafdnk nk mkldfm lkdamlkdmlkdmlk m klml km lkm kl."; + encode_websocket_frames(encoded, buffer2.data(), buffer2.size() + 1, WebSocketOpCode::Binary, 0); REQUIRE(encoded.size() == 1); TestWSHandler handler; @@ -269,12 +271,12 @@ TEST_CASE("HTTPParser1") } { // Decode a long frame which is split in two, after the first byte. - char* buffer = strdup("string with more than 127 characters: cdsklcmalkmc cdmslkc adslkccmkadsc adslkmc dsa ckdls cdksclknds lkndnc anslkc klsad ckl lksad clkas ccdascnkjancjnjkascsa cdascds clsad nclksad ncklsd clkadns lkc sadnlk cklsa cnaksld csad"); + std::string_view buffer = "string with more than 127 characters: cdsklcmalkmc cdmslkc adslkccmkadsc adslkmc dsa ckdls cdksclknds lkndnc anslkc klsad ckl lksad clkas ccdascnkjancjnjkascsa cdascds clsad nclksad ncklsd clkadns lkc sadnlk cklsa cnaksld csad"; std::vector encoded; - encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + encode_websocket_frames(encoded, buffer.data(), buffer.size() + 1, WebSocketOpCode::Binary, 0); REQUIRE(encoded.size() == 1); - for (size_t i = 1; i < strlen(buffer); ++i) { + for (size_t i = 1; i < buffer.size(); ++i) { char buffer1[1024]; char buffer2[1024]; memset(buffer1, 0xfa, 1024); @@ -292,13 +294,13 @@ TEST_CASE("HTTPParser1") } { // Decode a long frame which is split in two, after the first byte. - char* buffer = strdup("string with more than 127 characters: cdsklcmalkmc cdmslkc adslkccmkadsc adslkmc dsa ckdls cdksclknds lkndnc anslkc klsad ckl lksad clkas ccdascnkjancjnjkascsa cdascds clsad nclksad ncklsd clkadns lkc sadnlk cklsa cnaksld csad"); + std::string_view buffer = "string with more than 127 characters: cdsklcmalkmc cdmslkc adslkccmkadsc adslkmc dsa ckdls cdksclknds lkndnc anslkc klsad ckl lksad clkas ccdascnkjancjnjkascsa cdascds clsad nclksad ncklsd clkadns lkc sadnlk cklsa cnaksld csad"; std::vector encoded; - encode_websocket_frames(encoded, buffer, strlen(buffer) + 1, WebSocketOpCode::Binary, 0); + encode_websocket_frames(encoded, buffer.data(), buffer.size() + 1, WebSocketOpCode::Binary, 0); REQUIRE(encoded.size() == 1); - for (size_t i = 0; i < strlen(buffer) - 1; ++i) { - for (size_t j = i + 1; j < strlen(buffer); ++j) { + for (size_t i = 0; i < buffer.size() - 1; ++i) { + for (size_t j = i + 1; j < buffer.size(); ++j) { char buffer1[1024]; char buffer2[1024]; char buffer3[1024]; @@ -335,7 +337,7 @@ TEST_CASE("HTTPParser1") "Connection: Upgrade\r\n" "Access-Control-Allow-Origin: \"*\"\r\n" "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"; - int someSeed = 123; + std::string result = encode_websocket_handshake_request("/chat", "myprotocol", 13, "dGhlIHNhbXBsZSBub25jZQ=="); REQUIRE(result == checkRequest); From aa07fd8e01756a165e7557ab1b456910c426a1cd Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Wed, 14 Oct 2026 14:20:18 +0200 Subject: [PATCH 6/7] Delete deserialized ROOT objects in test_DataRefUtils The objects returned by the deserialization helpers were never deleted. Co-Authored-By: Claude Opus 5.5 --- Framework/Core/test/test_DataRefUtils.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Framework/Core/test/test_DataRefUtils.cxx b/Framework/Core/test/test_DataRefUtils.cxx index d4accde0fecf0..e5757c6de210e 100644 --- a/Framework/Core/test/test_DataRefUtils.cxx +++ b/Framework/Core/test/test_DataRefUtils.cxx @@ -38,6 +38,7 @@ TEST_CASE("PureRootTest") auto* outS = (TObjString*)buffer2.ReadObjectAny(storedClass); REQUIRE(outS != nullptr); REQUIRE(outS->GetString() == "test"); + delete outS; } // Simple test to do root deserialization. @@ -92,4 +93,5 @@ TEST_CASE("TestRootContainerSerialization") // the extracted object must be owning to avoid memory leaks // the get method takes care of this REQUIRE(s->IsOwner()); + delete tm; } From 7931f5e78a454eef2914ff8f06e32fa9df03ce2e Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Wed, 14 Oct 2026 14:20:18 +0200 Subject: [PATCH 7/7] Free input messages in test_InputRecord The inputs array allocated by the test was never released. Co-Authored-By: Claude Opus 5.5 --- Framework/Core/test/test_InputRecord.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Framework/Core/test/test_InputRecord.cxx b/Framework/Core/test/test_InputRecord.cxx index 6633bd40a30f8..eb03cee33ac47 100644 --- a/Framework/Core/test/test_InputRecord.cxx +++ b/Framework/Core/test/test_InputRecord.cxx @@ -167,6 +167,8 @@ TEST_CASE("TestInputRecord") REQUIRE(record.end().parts().size() == 0); // thus there is no element and begin == end REQUIRE(record.end().parts().begin() == record.end().parts().end()); + + std::ranges::for_each(inputs, [](auto* x){ free(x); }); } // TODO: