xo-arena: + DArena::unmap() + defeat DSElim
All checks were successful
CI / smoke-test (push) Successful in 1s
All checks were successful
CI / smoke-test (push) Successful in 1s
This commit is contained in:
parent
34d426da8e
commit
17dbb78a20
2 changed files with 40 additions and 10 deletions
|
|
@ -241,6 +241,22 @@ namespace xo {
|
||||||
**/
|
**/
|
||||||
void clear() noexcept;
|
void clear() noexcept;
|
||||||
|
|
||||||
|
/** release backing memory and reset bookkeeping to the empty state.
|
||||||
|
*
|
||||||
|
* Unmaps [@ref lo_, @ref hi_) (if mapped) and zeroes the bookkeeping
|
||||||
|
* fields {lo_, committed_z_, last_header_, free_, limit_, hi_,
|
||||||
|
* error_count_, last_error_}. @ref config_ (and page_z_/arena_align_z_)
|
||||||
|
* are left intact.
|
||||||
|
*
|
||||||
|
* Idempotent: a second call is a no-op (lo_ has been cleared).
|
||||||
|
* Invoked by ~DArena(); also safe to call on a live arena.
|
||||||
|
*
|
||||||
|
* Note: application code must not rely on observing the zeroed state
|
||||||
|
* after destruction (that would be UB) -- the zeroing is defensive,
|
||||||
|
* to avoid leaving dangling pointers behind.
|
||||||
|
**/
|
||||||
|
void unmap() noexcept;
|
||||||
|
|
||||||
/** swap contents (including configuration) with another arena **/
|
/** swap contents (including configuration) with another arena **/
|
||||||
void swap(DArena & other) noexcept;
|
void swap(DArena & other) noexcept;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include <xo/indentlog/print/tag.hpp>
|
#include <xo/indentlog/print/tag.hpp>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <new> // for std::launder()
|
||||||
#include <sys/mman.h> // for ::munmap()
|
#include <sys/mman.h> // for ::munmap()
|
||||||
#include <unistd.h> // for ::getpagesize()
|
#include <unistd.h> // for ::getpagesize()
|
||||||
#include <string.h> // for ::memset()
|
#include <string.h> // for ::memset()
|
||||||
|
|
@ -142,7 +143,8 @@ namespace xo {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
DArena::~DArena()
|
void
|
||||||
|
DArena::unmap() noexcept
|
||||||
{
|
{
|
||||||
if (lo_) {
|
if (lo_) {
|
||||||
//log && log("unmap [lo,hi)",
|
//log && log("unmap [lo,hi)",
|
||||||
|
|
@ -153,15 +155,27 @@ namespace xo {
|
||||||
::munmap(lo_, hi_ - lo_);
|
::munmap(lo_, hi_ - lo_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// hygiene
|
/* Mandatory hygiene: zero the bookkeeping tail so no dangling
|
||||||
lo_ = nullptr;
|
* pointers survive (e.g. after ~DArena() runs the dtor of a
|
||||||
committed_z_ = 0;
|
* stack-owned arena). config_, page_z_, arena_align_z_ are
|
||||||
// checkpoint_ = nullptr;
|
* preserved -- only {lo_ .. last_error_} get cleared.
|
||||||
free_ = nullptr;
|
*
|
||||||
limit_ = nullptr;
|
* The memset goes through a std::launder'd self pointer so the
|
||||||
hi_ = nullptr;
|
* compiler cannot prove it writes to the dying object and elide
|
||||||
error_count_ = 0;
|
* the stores as dead (gcc>=15 does that with a plain member
|
||||||
last_error_ = AllocError();
|
* assignment / un-laundered memset at -O1). All cleared fields
|
||||||
|
* are trivially-copyable, so byte-zeroing them is well-defined.
|
||||||
|
*/
|
||||||
|
DArena * self = std::launder(this);
|
||||||
|
byte * tail = reinterpret_cast<byte *>(&self->lo_);
|
||||||
|
byte * end = reinterpret_cast<byte *>(self) + sizeof(DArena);
|
||||||
|
|
||||||
|
::memset(tail, 0, end - tail);
|
||||||
|
}
|
||||||
|
|
||||||
|
DArena::~DArena()
|
||||||
|
{
|
||||||
|
this->unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto
|
auto
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue