diff --git a/include/xo/alloc2/alloc/IAllocator_Any.hpp b/include/xo/alloc2/alloc/IAllocator_Any.hpp index 06e7e58..bc91fca 100644 --- a/include/xo/alloc2/alloc/IAllocator_Any.hpp +++ b/include/xo/alloc2/alloc/IAllocator_Any.hpp @@ -35,6 +35,8 @@ namespace xo { // builtin methods typeseq _typeseq() const noexcept override { return s_typeseq; } + + // LCOV_EXCL_START void _drop(Opaque) const noexcept override { _fatal(); } // const methods @@ -58,9 +60,6 @@ namespace xo { [[noreturn]] value_type alloc(Opaque, typeseq, std::size_t) const override { _fatal(); } [[noreturn]] value_type super_alloc(Opaque, typeseq, std::size_t) const override { _fatal(); } [[noreturn]] value_type sub_alloc(Opaque, std::size_t, bool) const override { _fatal(); } -#ifdef OBSOLETE - [[noreturn]] value_type alloc_copy(Opaque, value_type) const override { _fatal(); } -#endif [[noreturn]] void clear(Opaque) const override { _fatal(); } [[noreturn]] void barrier_assign_aux(Opaque, void *, @@ -69,6 +68,7 @@ namespace xo { private: [[noreturn]] static void _fatal(); + // LCOV_EXCL_STOP public: static typeseq s_typeseq; diff --git a/include/xo/alloc2/arena/IAllocator_DArena.hpp b/include/xo/alloc2/arena/IAllocator_DArena.hpp index 5a3ad8f..a178e5a 100644 --- a/include/xo/alloc2/arena/IAllocator_DArena.hpp +++ b/include/xo/alloc2/arena/IAllocator_DArena.hpp @@ -78,7 +78,7 @@ namespace xo { void * parent, AGCObject * lhs_iface, void ** lhs_data, AGCObject * rhs_iface, void * rhs_data); - static void destruct_data(DArena &); + //static void destruct_data(DArena &); }; // template <> diff --git a/include/xo/alloc2/gc/RCollector.hpp b/include/xo/alloc2/gc/RCollector.hpp index b7c54d4..2818957 100644 --- a/include/xo/alloc2/gc/RCollector.hpp +++ b/include/xo/alloc2/gc/RCollector.hpp @@ -52,7 +52,7 @@ public: void * alloc_copy_for(const T * src) noexcept { return O::iface()->alloc_copy(O::data(), (std::byte *)const_cast(src)); } - + /** convenience template for move-constructible T (this is common) **/ template T * std_move_for(T * src) noexcept { @@ -62,28 +62,28 @@ public: } return nullptr; } - + /** forward faceted object pointer in place. Defined in GCObject.hpp to avoid #include cycle **/ template void forward_inplace(obj * p_obj); - + /** another convenience template for forwarding. * Defined in RGCObject.hpp to avoid #include cycle. **/ template void forward_inplace(DRepr ** pp_repr); - + /** convenience template where pointer requires pivot **/ template requires (!std::is_same_v) void forward_pivot_inplace(obj * p_obj); - + /** add root @p p_root **/ template void add_gc_root(obj * p_root) { O::iface()->add_gc_root_poly(O::data(), (obj *)p_root); } - + /** remove root @p p_root **/ template void remove_gc_root(obj * p_root) { @@ -91,6 +91,7 @@ public: } // builtin methods + bool _has_null_vptr() const noexcept { return O::iface()->_has_null_vptr(); } typeseq _typeseq() const noexcept { return O::iface()->_typeseq(); } void _drop() const noexcept { O::iface()->_drop(O::data()); } diff --git a/src/alloc2/IAllocator_Any.cpp b/src/alloc2/IAllocator_Any.cpp index 813973c..d8b1aab 100644 --- a/src/alloc2/IAllocator_Any.cpp +++ b/src/alloc2/IAllocator_Any.cpp @@ -14,6 +14,7 @@ namespace xo { namespace mm { + // LCOV_EXCL_START void IAllocator_Any::_fatal() { @@ -29,6 +30,7 @@ namespace xo { std::terminate(); } + // LCOV_EXCL_STOP typeseq IAllocator_Any::s_typeseq = typeseq::id(); diff --git a/src/alloc2/IAllocator_DArena.cpp b/src/alloc2/IAllocator_DArena.cpp index 3f205a9..ea60b69 100644 --- a/src/alloc2/IAllocator_DArena.cpp +++ b/src/alloc2/IAllocator_DArena.cpp @@ -173,11 +173,13 @@ namespace xo { *lhs_data = rhs_data; } +#ifdef OBSOLETE void IAllocator_DArena::destruct_data(DArena & s) { s.~DArena(); } +#endif } /*namespace mm*/ } /*namespace xo*/ diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index af2d319..c885daa 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -6,6 +6,7 @@ set(UTEST_SRCS alloc2_utest_main.cpp objectmodel.test.cpp arena.test.cpp + IAllocator_Any.test.cpp DArenaIterator.test.cpp # Collector.test.cpp # DX1CollectorIterator.test.cpp diff --git a/utest/IAllocator_Any.test.cpp b/utest/IAllocator_Any.test.cpp new file mode 100644 index 0000000..5d23c6e --- /dev/null +++ b/utest/IAllocator_Any.test.cpp @@ -0,0 +1,29 @@ +/** @file IAllocator_Any.test.cpp + * + * @author Roland Conybeare, May 2026 + **/ + +#include +#include +#include +#include +#include + +namespace xo { + using xo::mm::AAllocator; + + namespace ut { + + TEST_CASE("IAllocator_Any", "[alloc2][death]") + { + // null allocator + obj alloc_any; + + // NOTE: tried using a fork() strategy to verify termination, + // but child process doesn't get measured by gcov + } + + } /*namespace ut*/ +} /*namespace xo*/ + +/* end IAllocator_Any.test.cpp */ diff --git a/utest/arena.test.cpp b/utest/arena.test.cpp index 0a1c3e9..95077f6 100644 --- a/utest/arena.test.cpp +++ b/utest/arena.test.cpp @@ -97,6 +97,8 @@ namespace xo { //obj a1o{&arena}; auto a1o = with_facet::mkobj(&arena); + REQUIRE(!a1o._has_null_vptr()); + REQUIRE(a1o); REQUIRE(a1o.iface() != nullptr); REQUIRE(a1o.data() != nullptr); @@ -110,6 +112,12 @@ namespace xo { REQUIRE(a1o.size() == 0); REQUIRE(a1o.committed() == 0); REQUIRE(a1o.allocated() == 0); + + a1o._drop(); + { + REQUIRE(a1o.allocated() == 0); + REQUIRE(a1o.committed() == 0); + } } TEST_CASE("allocator-expand-1", "[alloc2][AAllocator]") @@ -122,6 +130,8 @@ namespace xo { //obj a1o{&arena}; auto a1o = with_facet::mkobj(&arena); + REQUIRE(!a1o._has_null_vptr()); + REQUIRE(a1o.available() == 0); REQUIRE(a1o.allocated() == 0); @@ -141,6 +151,11 @@ namespace xo { REQUIRE(a1o.available() == a1o.committed()); REQUIRE(a1o.allocated() == 0); + a1o._drop(); + { + REQUIRE(a1o.allocated() == 0); + REQUIRE(a1o.committed() == 0); + } } TEST_CASE("allocator-alloc-1", "[alloc2][AAllocator]") @@ -152,6 +167,8 @@ namespace xo { DArena arena = DArena::map(cfg); auto a1o = with_facet::mkobj(&arena); + REQUIRE(!a1o._has_null_vptr()); + REQUIRE(a1o.reserved() >= cfg.size_); REQUIRE(a1o.committed() == 0); REQUIRE(a1o.available() == 0); @@ -180,6 +197,12 @@ namespace xo { REQUIRE(a1o.allocated() <= a1o.committed()); REQUIRE(a1o.allocated() + a1o.available() == a1o.committed()); REQUIRE(a1o.committed() <= a1o.reserved()); + + a1o._drop(); + { + REQUIRE(a1o.allocated() == 0); + REQUIRE(a1o.committed() == 0); + } } TEST_CASE("allocator-alloc-2", "[alloc2][Allocator]") @@ -202,6 +225,8 @@ namespace xo { //obj a1o{&arena}; auto a1o = with_facet::mkobj(&arena); + REQUIRE(!a1o._has_null_vptr()); + REQUIRE(a1o.reserved() >= cfg.size_); REQUIRE(a1o.committed() == 0); REQUIRE(a1o.available() == 0); @@ -244,19 +269,26 @@ namespace xo { } a1o.clear(); + { + // allocated size got reset + REQUIRE(a1o.allocated() == 0); + // committed size unchanged + REQUIRE(a1o.committed() == committed0_z); + REQUIRE(a1o.last_error().error_ == error::ok); + REQUIRE(a1o.last_error().error_seq_ == 0); - // allocated size got reset - REQUIRE(a1o.allocated() == 0); - // committed size unchanged - REQUIRE(a1o.committed() == committed0_z); - REQUIRE(a1o.last_error().error_ == error::ok); - REQUIRE(a1o.last_error().error_seq_ == 0); + // allocator no longer contains m0 (now points to unallocated but committed memory + // (not exposed via AAllocator! + // REQUIRE(a1o.contains_allocated(m0) == false); - // allocator no longer contains m0 (now points to unallocated but committed memory - // (not exposed via AAllocator! - // REQUIRE(a1o.contains_allocated(m0) == false); + REQUIRE(a1o.contains(m0)); + } - REQUIRE(a1o.contains(m0)); + a1o._drop(); + { + REQUIRE(a1o.allocated() == 0); + REQUIRE(a1o.committed() == 0); + } } TEST_CASE("allocator-alloc-3", "[alloc2][Allocator]") @@ -279,6 +311,8 @@ namespace xo { //obj a1o{&arena}; auto a1o = with_facet::mkobj(&arena); + REQUIRE(!a1o._has_null_vptr()); + REQUIRE(a1o.reserved() >= cfg.size_); REQUIRE(a1o.committed() == 0); REQUIRE(a1o.available() == 0); @@ -301,23 +335,30 @@ namespace xo { header_type* header = (header_type*)(m0 - sizeof(header_type)); size_t pad = padding::with_padding(z0) - z0; byte * guard1 = m0 + z0 + pad; + { + REQUIRE(a1o.contains(guard0)); + REQUIRE(a1o.contains(header)); + REQUIRE(cfg.header_.size(*header) == padding::with_padding(z0)); + //REQUIRE(((*header) & cfg.header_size_mask_) == padding::with_padding(z0)); - REQUIRE(a1o.contains(guard0)); - REQUIRE(a1o.contains(header)); - REQUIRE(cfg.header_.size(*header) == padding::with_padding(z0)); - //REQUIRE(((*header) & cfg.header_size_mask_) == padding::with_padding(z0)); + REQUIRE(a1o.last_error().error_ == error::ok); + REQUIRE(a1o.last_error().error_seq_ == 0); - REQUIRE(a1o.last_error().error_ == error::ok); - REQUIRE(a1o.last_error().error_seq_ == 0); + REQUIRE(a1o.allocated() == (cfg.header_.guard_z_ + + sizeof(header_type) + + z0 + + pad + + cfg.header_.guard_z_)); + REQUIRE(a1o.allocated() <= a1o.committed()); + REQUIRE(a1o.allocated() + a1o.available() == a1o.committed()); + REQUIRE(a1o.committed() <= a1o.reserved()); + } - REQUIRE(a1o.allocated() == (cfg.header_.guard_z_ - + sizeof(header_type) - + z0 - + pad - + cfg.header_.guard_z_)); - REQUIRE(a1o.allocated() <= a1o.committed()); - REQUIRE(a1o.allocated() + a1o.available() == a1o.committed()); - REQUIRE(a1o.committed() <= a1o.reserved()); + a1o._drop(); + { + REQUIRE(a1o.allocated() == 0); + REQUIRE(a1o.committed() == 0); + } } TEST_CASE("allocator-fail-1", "[alloc2][AAllocator]") @@ -332,6 +373,8 @@ namespace xo { REQUIRE(cfg.size_ <= cfg.hugepage_z_); + REQUIRE(!a1o._has_null_vptr()); + REQUIRE(a1o.reserved() >= cfg.size_); REQUIRE(a1o.committed() == 0); REQUIRE(a1o.available() == 0); @@ -339,17 +382,22 @@ namespace xo { size_t z0 = cfg.hugepage_z_ + 1; byte * m0 = a1o.alloc(typeseq::sentinel(), z0); - - REQUIRE(!m0); - AllocError err = a1o.last_error(); + { + REQUIRE(!m0); + REQUIRE(err.error_ == error::reserve_exhausted); + REQUIRE(err.error_seq_ == 1); + REQUIRE(err.request_z_ >= z0); + REQUIRE(err.request_z_ < z0 + padding::c_alloc_alignment); + REQUIRE(err.committed_z_ == 0); + REQUIRE(err.reserved_z_ == arena.reserved()); + } - REQUIRE(err.error_ == error::reserve_exhausted); - REQUIRE(err.error_seq_ == 1); - REQUIRE(err.request_z_ >= z0); - REQUIRE(err.request_z_ < z0 + padding::c_alloc_alignment); - REQUIRE(err.committed_z_ == 0); - REQUIRE(err.reserved_z_ == arena.reserved()); + a1o._drop(); + { + REQUIRE(a1o.allocated() == 0); + REQUIRE(a1o.committed() == 0); + } } } /*namespace ut*/ } /*namespace xo*/