From a9b6b34932a3c29809ce2ca6dbb30398c85ceabe Mon Sep 17 00:00:00 2001 From: Edwin Rodriguez Date: Fri, 1 Aug 2025 14:20:36 -0400 Subject: [PATCH] os: Page class: disable move operations and improve custom delete operator for proper memory management Fix UB in Page 'operator delete' to eliminate uninitialized memory access Fixes: https://tracker.ceph.com/issues/72404 Signed-off-by: Edwin Rodriguez --- src/os/memstore/PageSet.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/os/memstore/PageSet.h b/src/os/memstore/PageSet.h index 71954e574642..b7e7e7304a4f 100644 --- a/src/os/memstore/PageSet.h +++ b/src/os/memstore/PageSet.h @@ -75,12 +75,24 @@ struct Page { // copy disabled Page(const Page&) = delete; const Page& operator=(const Page&) = delete; + Page(Page&&) = delete; + Page& operator=(Page&&) = delete; private: // private constructor, use create() instead Page(char *data, uint64_t offset) : data(data), offset(offset), nrefs(1) {} - static void operator delete(void *p) { - delete[] reinterpret_cast(p)->data; + // Custom delete operator that uses std::destroying_delete_t to ensure proper cleanup + // of the buffer-Page layout. Since Page is placed at the end of a larger allocated buffer + // containing both the data array and the Page object itself, we need to: + // 1. Store the buffer pointer before destroying the Page object + // 2. Call the Page destructor explicitly to destroy the object in-place + // 3. Delete the entire buffer containing both data and Page + // Without std::destroying_delete_t, the compiler would call the destructor + // before our delete operator, leading to unitialized memory access. + static void operator delete(Page *p, std::destroying_delete_t) { + auto* buffer = p->data; + p->~Page(); + delete[] buffer; } }; -- 2.47.3