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 <k.chai@proxmox.com>
# 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
int DB::Destroy(const DoutPrefixProvider *dpp)
{
- if (!db)
- return 0;
-
- stopGC();
-
- closeDB(dpp);
+ if (db) {
+ stopGC();
+ closeDB(dpp);
+ }
{
const std::lock_guard lk(mtx);
return 0;
}
+ // Delete the ObjectOp object to prevent memory leak
+ delete iter->second;
DB::objectmap.erase(iter);
return 0;