summaryrefslogtreecommitdiff
path: root/absl/container/internal/raw_hash_set_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/container/internal/raw_hash_set_test.cc')
-rw-r--r--absl/container/internal/raw_hash_set_test.cc84
1 files changed, 74 insertions, 10 deletions
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index d194ca1b..4e67b79e 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -49,8 +49,10 @@
#include "absl/container/internal/hash_policy_testing.h"
#include "absl/container/internal/hashtable_debug.h"
#include "absl/container/internal/test_allocator.h"
+#include "absl/functional/function_ref.h"
#include "absl/log/log.h"
#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -409,19 +411,15 @@ struct StringTable
using Base::Base;
};
-struct IntTable
- : raw_hash_set<IntPolicy, hash_default_hash<int64_t>,
- std::equal_to<int64_t>, std::allocator<int64_t>> {
- using Base = typename IntTable::raw_hash_set;
+template <typename T>
+struct ValueTable : raw_hash_set<ValuePolicy<T>, hash_default_hash<T>,
+ std::equal_to<T>, std::allocator<T>> {
+ using Base = typename ValueTable::raw_hash_set;
using Base::Base;
};
-struct Uint8Table
- : raw_hash_set<Uint8Policy, hash_default_hash<uint8_t>,
- std::equal_to<uint8_t>, std::allocator<uint8_t>> {
- using Base = typename Uint8Table::raw_hash_set;
- using Base::Base;
-};
+using IntTable = ValueTable<int64_t>;
+using Uint8Table = ValueTable<uint8_t>;
template <typename T>
struct CustomAlloc : std::allocator<T> {
@@ -2489,6 +2487,72 @@ using RawHashSetAlloc = raw_hash_set<IntPolicy, hash_default_hash<int64_t>,
TEST(Table, AllocatorPropagation) { TestAllocPropagation<RawHashSetAlloc>(); }
+struct ConstructCaller {
+ explicit ConstructCaller(int v) : val(v) {}
+ ConstructCaller(int v, absl::FunctionRef<void()> func) : val(v) { func(); }
+ template <typename H>
+ friend H AbslHashValue(H h, const ConstructCaller& d) {
+ return H::combine(std::move(h), d.val);
+ }
+ bool operator==(const ConstructCaller& c) const { return val == c.val; }
+
+ int val;
+};
+
+struct DestroyCaller {
+ explicit DestroyCaller(int v) : val(v) {}
+ DestroyCaller(int v, absl::FunctionRef<void()> func)
+ : val(v), destroy_func(func) {}
+ DestroyCaller(DestroyCaller&& that)
+ : val(that.val), destroy_func(std::move(that.destroy_func)) {
+ that.Deactivate();
+ }
+ ~DestroyCaller() {
+ if (destroy_func) (*destroy_func)();
+ }
+ void Deactivate() { destroy_func = absl::nullopt; }
+
+ template <typename H>
+ friend H AbslHashValue(H h, const DestroyCaller& d) {
+ return H::combine(std::move(h), d.val);
+ }
+ bool operator==(const DestroyCaller& d) const { return val == d.val; }
+
+ int val;
+ absl::optional<absl::FunctionRef<void()>> destroy_func;
+};
+
+#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || defined(ABSL_HAVE_MEMORY_SANITIZER)
+TEST(Table, ReentrantCallsFail) {
+ constexpr const char* kDeathMessage =
+ "use-after-poison|use-of-uninitialized-value";
+ {
+ ValueTable<ConstructCaller> t;
+ t.insert(ConstructCaller{0});
+ auto erase_begin = [&] { t.erase(t.begin()); };
+ EXPECT_DEATH_IF_SUPPORTED(t.emplace(1, erase_begin), kDeathMessage);
+ }
+ {
+ ValueTable<DestroyCaller> t;
+ t.insert(DestroyCaller{0});
+ auto find_0 = [&] { t.find(DestroyCaller{0}); };
+ t.insert(DestroyCaller{1, find_0});
+ for (int i = 10; i < 20; ++i) t.insert(DestroyCaller{i});
+ EXPECT_DEATH_IF_SUPPORTED(t.clear(), kDeathMessage);
+ for (auto& elem : t) elem.Deactivate();
+ }
+ {
+ ValueTable<DestroyCaller> t;
+ t.insert(DestroyCaller{0});
+ auto insert_1 = [&] { t.insert(DestroyCaller{1}); };
+ t.insert(DestroyCaller{1, insert_1});
+ for (int i = 10; i < 20; ++i) t.insert(DestroyCaller{i});
+ EXPECT_DEATH_IF_SUPPORTED(t.clear(), kDeathMessage);
+ for (auto& elem : t) elem.Deactivate();
+ }
+}
+#endif
+
} // namespace
} // namespace container_internal
ABSL_NAMESPACE_END