From 79e048ee25496aec721285478f038130d9286a3c Mon Sep 17 00:00:00 2001 From: bneradt Date: Wed, 13 May 2026 12:52:23 -0500 Subject: [PATCH] Avoid confusing AIO callback lifetime test Coverity reports the AIO callback lifetime regression test as a leak and bad free because the test heap-allocates an owner object whose member callback is destroyed indirectly during completion. The runtime behavior is intentional, but the ownership pattern makes the regression test look invalid to static analysis. This updates the fixture so the owner has normal stack lifetime and owns the callback through a unique_ptr. The completion handler still destroys the callback before AIOCallback::io_complete() returns, preserving the lifetime coverage while making the allocation and free visible to analysis. --- src/iocore/aio/unit_tests/test_AIOCallback.cc | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/iocore/aio/unit_tests/test_AIOCallback.cc b/src/iocore/aio/unit_tests/test_AIOCallback.cc index f75335f764b..39fc1dede17 100644 --- a/src/iocore/aio/unit_tests/test_AIOCallback.cc +++ b/src/iocore/aio/unit_tests/test_AIOCallback.cc @@ -23,6 +23,8 @@ #include +#include + #include "iocore/aio/AIO.h" #include "iocore/eventsystem/Event.h" @@ -30,26 +32,27 @@ namespace { struct AIOCompletionOwner : Continuation { - AIOCallback callback; - bool *completed = nullptr; + std::unique_ptr callback; + bool *completed = nullptr; - explicit AIOCompletionOwner(bool &completion_flag) : Continuation(nullptr), completed(&completion_flag) + explicit AIOCompletionOwner(bool &completion_flag) + : Continuation(nullptr), callback(std::make_unique()), completed(&completion_flag) { SET_HANDLER(&AIOCompletionOwner::handle_aio_complete); - callback.action = this; - callback.aiocb.aio_nbytes = 0; - callback.aio_result = 0; + callback->action = this; + callback->aiocb.aio_nbytes = 0; + callback->aio_result = 0; } int handle_aio_complete(int event, void *data) { CHECK(event == AIO_EVENT_DONE); - CHECK(data == &callback); + CHECK(data == callback.get()); *completed = true; - delete this; + callback.reset(); return EVENT_DONE; } }; @@ -84,11 +87,11 @@ struct DeletionTrackedAIOCallback : AIOCallback { } // namespace -TEST_CASE("AIOCallback completion tolerates owner deletion", "[iocore][aio]") +TEST_CASE("AIOCallback completion tolerates callback deletion", "[iocore][aio]") { - bool completed = false; - auto owner = new AIOCompletionOwner(completed); - auto callback = &owner->callback; + bool completed = false; + AIOCompletionOwner owner(completed); + auto *callback = owner.callback.get(); // Without ASan, a broken implementation can still pass because the stale value of from_ts_api is typically false. CHECK(callback->io_complete(EVENT_NONE, nullptr) == EVENT_DONE);