From a89e51ccca32a0535471d3cc2e1171ca65f6c97f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 10 Sep 2026 09:42:12 +0200 Subject: kstd/vector: fix UB in test suite --- libs/kstd/kstd/test_support/test_types.hpp | 56 ++++++++++++++++++++++++++++++ libs/kstd/kstd/vector.tests.cpp | 34 ++++++++++++------ 2 files changed, 79 insertions(+), 11 deletions(-) (limited to 'libs') diff --git a/libs/kstd/kstd/test_support/test_types.hpp b/libs/kstd/kstd/test_support/test_types.hpp index 8231fd3b..baf5e853 100644 --- a/libs/kstd/kstd/test_support/test_types.hpp +++ b/libs/kstd/kstd/test_support/test_types.hpp @@ -13,6 +13,28 @@ namespace kstd::tests //! This type is designed to test move and copy semantics of standard library containers implemented in kstd. struct special_member_tracker { + struct counters + { + //! A counter to track how many times an instance of this type was default constructed. + std::size_t default_constructed{0}; + //! A counter to track how many times an instance of this type was copy constructed. + std::size_t copy_constructed{0}; + //! A counter to track how many times an instance of this type was move constructed. + std::size_t move_constructed{0}; + //! A counter to track how many times an instance of this type was value constructed. + std::size_t value_constructed{0}; + //! A counter to track how many times an instance of this type was copy assigned. + std::size_t copy_assigned{0}; + //! A counter to track how many times an instance of this type was move assigned. + std::size_t move_assigned{0}; + //! A counter to track how many times an instance of this type was destroyed. + std::size_t destroyed{0}; + //! A counter to track how many times an instance of this type was copied from another instance. + std::size_t copied_from{0}; + //! A counter to track how many times an instance of this type was moved from another instance. + std::size_t moved_from{0}; + } * external = nullptr; + //! A value indicating that the object was moved from. constexpr auto static moved_from_v = -1; @@ -47,7 +69,15 @@ namespace kstd::tests { value = other.value; ++copy_assigned_count; + if (external) + { + ++external->copy_assigned; + } ++other.copied_from_count; + if (other.external) + { + ++other.external->copied_from; + } } return *this; } @@ -61,8 +91,16 @@ namespace kstd::tests { value = other.value; ++move_assigned_count; + if (external) + { + ++external->move_assigned; + } other.value = moved_from_v; ++other.moved_from_count; + if (other.external) + { + ++other.external->moved_from; + } } return *this; } @@ -70,6 +108,24 @@ namespace kstd::tests ~special_member_tracker() { ++destroyed_count; + if (external) + { + ++external->destroyed; + } + } + + auto set_external_counters(counters & counters) noexcept + { + external = &counters; + external->default_constructed = default_constructed_count; + external->copy_constructed = copy_constructed_count; + external->move_constructed = move_constructed_count; + external->value_constructed = value_constructed_count; + external->copy_assigned = copy_assigned_count; + external->move_assigned = move_assigned_count; + external->destroyed = destroyed_count; + external->copied_from = copied_from_count; + external->moved_from = moved_from_count; } auto reset_counts() -> void diff --git a/libs/kstd/kstd/vector.tests.cpp b/libs/kstd/kstd/vector.tests.cpp index 24598bf9..ed0695fb 100644 --- a/libs/kstd/kstd/vector.tests.cpp +++ b/libs/kstd/kstd/vector.tests.cpp @@ -1628,6 +1628,9 @@ SCENARIO("Vector modifier move semantics", "[vector]") elem.reset_counts(); } + auto counters = kstd::tests::special_member_tracker::counters{}; + v[2].set_external_counters(counters); + auto it = v.erase(v.cbegin() + 1); THEN("the subsequent elements are move-assigned leftwards") @@ -1642,8 +1645,8 @@ SCENARIO("Vector modifier move semantics", "[vector]") REQUIRE(v[1].move_assigned_count == 1); REQUIRE(v[1].copy_assigned_count == 0); - REQUIRE(v.data()[2].destroyed_count == 1); - REQUIRE(v.data()[2].moved_from_count == 1); + REQUIRE(counters.destroyed == 1); + REQUIRE(counters.moved_from == 1); REQUIRE(it == v.begin() + 1); } @@ -1656,6 +1659,9 @@ SCENARIO("Vector modifier move semantics", "[vector]") elem.reset_counts(); } + auto counters = kstd::tests::special_member_tracker::counters{}; + v[2].set_external_counters(counters); + auto it = v.erase(v.cend() - 1); THEN("no elements are moved, just the last element destroyed") @@ -1674,9 +1680,9 @@ SCENARIO("Vector modifier move semantics", "[vector]") REQUIRE(v[1].move_assigned_count == 0); REQUIRE(v[1].copy_assigned_count == 0); - REQUIRE(v.data()[2].destroyed_count == 1); - REQUIRE(v.data()[2].moved_from_count == 0); - REQUIRE(v.data()[2].copied_from_count == 0); + REQUIRE(counters.destroyed == 1); + REQUIRE(counters.moved_from == 0); + REQUIRE(counters.copied_from == 0); REQUIRE(it == v.end()); } @@ -1692,6 +1698,12 @@ SCENARIO("Vector modifier move semantics", "[vector]") elem.reset_counts(); } + auto counters3 = kstd::tests::special_member_tracker::counters{}; + v[3].set_external_counters(counters3); + + auto counters4 = kstd::tests::special_member_tracker::counters{}; + v[4].set_external_counters(counters4); + auto it = v.erase(v.cbegin() + 1, v.cbegin() + 3); THEN("the specified elements are destroyed and subsequent elements are move-assigned leftwards") @@ -1716,13 +1728,13 @@ SCENARIO("Vector modifier move semantics", "[vector]") REQUIRE(v[2].move_assigned_count == 1); REQUIRE(v[2].copy_assigned_count == 0); - REQUIRE(v.data()[3].destroyed_count == 1); - REQUIRE(v.data()[3].moved_from_count == 1); - REQUIRE(v.data()[3].copied_from_count == 0); + REQUIRE(counters3.destroyed == 1); + REQUIRE(counters3.moved_from == 1); + REQUIRE(counters3.copied_from == 0); - REQUIRE(v.data()[4].destroyed_count == 1); - REQUIRE(v.data()[4].moved_from_count == 1); - REQUIRE(v.data()[4].copied_from_count == 0); + REQUIRE(counters4.destroyed == 1); + REQUIRE(counters4.moved_from == 1); + REQUIRE(counters4.copied_from == 0); REQUIRE(it == v.begin() + 1); } -- cgit v1.2.3