From b827a7113a7a79f62c18aaf1ead1fa17e16ce7bf Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Fri, 9 Jan 2026 12:40:39 +0800 Subject: [PATCH] rgw/dbstore: fix memory leaks in unittest_dbstore_tests Fix memory leaks detected by AddressSanitizer in unittest_dbstore_tests. The test was failing with ASan enabled due to SQLObjectOp objects not being properly cleaned up. ASan reported the following leaks: Direct leak of 200 byte(s) in 1 object(s) allocated from: #0 operator new(unsigned long) #1 SQLGetBucket::Execute(DoutPrefixProvider const*, rgw::store::DBOpParams*) /src/rgw/driver/dbstore/sqlite/sqliteDB.cc:1689 #2 rgw::store::DB::ProcessOp(DoutPrefixProvider const*, ...) /src/rgw/driver/dbstore/common/dbstore.cc:258 Direct leak of 200 byte(s) in 1 object(s) allocated from: #0 operator new(unsigned long) #1 SQLInsertBucket::Execute(DoutPrefixProvider const*, rgw::store::DBOpParams*) /src/rgw/driver/dbstore/sqlite/sqliteDB.cc:1433 #2 rgw::store::DB::ProcessOp(DoutPrefixProvider const*, ...) /src/rgw/driver/dbstore/common/dbstore.cc:258 SUMMARY: AddressSanitizer: 460550 byte(s) leaked in 1823 allocation(s). Root cause: The DB::Destroy() method had an early return when the db pointer was NULL, preventing cleanup of the objectmap which stores SQLObjectOp pointers. These objects were allocated during test execution but never freed. Changes: - Modified DB::Destroy() to always clean up objectmap even when db is NULL - Added explicit delete in objectmapDelete() for consistency - Added lsan suppression for SQLite internal allocations (indirect leaks) After the fix, all direct leaks are eliminated. Only indirect leaks from SQLite's internal memory management remain, which are now suppressed. Test results: - Before: 460,550 bytes leaked (including 2 direct leaks of 200 bytes each) - After: 0 direct leaks, unittest_dbstore_tests passes with ASan Signed-off-by: Kefu Chai --- qa/lsan.supp | 4 ++++ src/rgw/driver/dbstore/common/dbstore.cc | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/qa/lsan.supp b/qa/lsan.supp index 055a703b0fcb5..9418cc5de2144 100644 --- a/qa/lsan.supp +++ b/qa/lsan.supp @@ -34,3 +34,7 @@ leak:^PyModule_ExecDef # following suppression mirrors qa/valgrind.supp # ignore ec plugin factory (FIXME SOMEDAY) leak:^ceph::ErasureCodePluginRegistry::load + +# SQLite internal allocations +# These are indirect leaks from SQLite's internal memory management +leak:libsqlite3.so diff --git a/src/rgw/driver/dbstore/common/dbstore.cc b/src/rgw/driver/dbstore/common/dbstore.cc index 4d55ee97c5724..6db081ca3043d 100644 --- a/src/rgw/driver/dbstore/common/dbstore.cc +++ b/src/rgw/driver/dbstore/common/dbstore.cc @@ -75,12 +75,10 @@ int DB::stopGC() { int DB::Destroy(const DoutPrefixProvider *dpp) { - if (!db) - return 0; - - stopGC(); - - closeDB(dpp); + if (db) { + stopGC(); + closeDB(dpp); + } { const std::lock_guard lk(mtx); @@ -219,6 +217,8 @@ int DB::objectmapDelete(const DoutPrefixProvider *dpp, string bucket) return 0; } + // Delete the ObjectOp object to prevent memory leak + delete iter->second; DB::objectmap.erase(iter); return 0; -- 2.47.3