This is an automated email from the ASF dual-hosted git repository.
bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new f0970ef5ff Avoid confusing AIO callback lifetime test (#13159)
f0970ef5ff is described below
commit f0970ef5ffb43782992917c5d30e767b0a02a945
Author: Brian Neradt <[email protected]>
AuthorDate: Wed May 13 16:22:08 2026 -0500
Avoid confusing AIO callback lifetime test (#13159)
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 f75335f764..39fc1dede1 100644
--- a/src/iocore/aio/unit_tests/test_AIOCallback.cc
+++ b/src/iocore/aio/unit_tests/test_AIOCallback.cc
@@ -23,6 +23,8 @@
#include <catch2/catch_test_macros.hpp>
+#include <memory>
+
#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<AIOCallback> 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<AIOCallback>()),
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);