aboutsummaryrefslogtreecommitdiff
path: root/absl/container/internal/raw_hash_set_test.cc
diff options
context:
space:
mode:
authorEvan Brown <ezb@google.com>2022-12-19 11:53:21 -0800
committerCopybara-Service <copybara-worker@google.com>2022-12-19 11:54:08 -0800
commita1ec5d62e70994d4d488d827f4e44a9a4165fd36 (patch)
tree1c8e0e5b8d8a351f50005da33254a6531b98882e /absl/container/internal/raw_hash_set_test.cc
parentdbc61b490c5c259df33af59f9922a7224341397b (diff)
downloadabseil-a1ec5d62e70994d4d488d827f4e44a9a4165fd36.tar.gz
abseil-a1ec5d62e70994d4d488d827f4e44a9a4165fd36.tar.bz2
abseil-a1ec5d62e70994d4d488d827f4e44a9a4165fd36.zip
In sanitizer mode, add generations to swisstable iterators and backing arrays so that we can detect invalid iterator use.
PiperOrigin-RevId: 496455788 Change-Id: I83df92828098a3ef1181b4e454f3ac5d3ac7a2f2
Diffstat (limited to 'absl/container/internal/raw_hash_set_test.cc')
-rw-r--r--absl/container/internal/raw_hash_set_test.cc96
1 files changed, 76 insertions, 20 deletions
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index eb0757b2..3bfb15f1 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -476,27 +476,37 @@ TEST(Table, EmptyFunctorOptimization) {
size_t dummy;
};
- if (std::is_empty<HashtablezInfoHandle>::value) {
- EXPECT_EQ(sizeof(MockTableInfozDisabled),
- sizeof(raw_hash_set<StringPolicy, StatelessHash,
- std::equal_to<absl::string_view>,
- std::allocator<int>>));
-
- EXPECT_EQ(sizeof(MockTableInfozDisabled) + sizeof(StatefulHash),
- sizeof(raw_hash_set<StringPolicy, StatefulHash,
- std::equal_to<absl::string_view>,
- std::allocator<int>>));
- } else {
- EXPECT_EQ(sizeof(MockTable),
- sizeof(raw_hash_set<StringPolicy, StatelessHash,
- std::equal_to<absl::string_view>,
- std::allocator<int>>));
+ struct GenerationData {
+ size_t reserved_growth;
+ GenerationType* generation;
+ };
- EXPECT_EQ(sizeof(MockTable) + sizeof(StatefulHash),
- sizeof(raw_hash_set<StringPolicy, StatefulHash,
- std::equal_to<absl::string_view>,
- std::allocator<int>>));
- }
+// Ignore unreachable-code warning. Compiler thinks one branch of each ternary
+// conditional is unreachable.
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+ constexpr size_t mock_size = std::is_empty<HashtablezInfoHandle>()
+ ? sizeof(MockTableInfozDisabled)
+ : sizeof(MockTable);
+ constexpr size_t generation_size =
+ SwisstableGenerationsEnabled() ? sizeof(GenerationData) : 0;
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+ EXPECT_EQ(
+ mock_size + generation_size,
+ sizeof(
+ raw_hash_set<StringPolicy, StatelessHash,
+ std::equal_to<absl::string_view>, std::allocator<int>>));
+
+ EXPECT_EQ(
+ mock_size + sizeof(StatefulHash) + generation_size,
+ sizeof(
+ raw_hash_set<StringPolicy, StatefulHash,
+ std::equal_to<absl::string_view>, std::allocator<int>>));
}
TEST(Table, Empty) {
@@ -2236,6 +2246,52 @@ TEST(Table, AlignOne) {
}
}
+// Invalid iterator use can trigger heap-use-after-free in asan,
+// use-of-uninitialized-value in msan, or invalidated iterator assertions.
+constexpr const char* kInvalidIteratorDeathMessage =
+ "heap-use-after-free|use-of-uninitialized-value|invalidated iterator";
+
+#if defined(__clang__) && defined(_MSC_VER)
+constexpr bool kLexan = true;
+#else
+constexpr bool kLexan = false;
+#endif
+
+TEST(Table, InvalidIteratorUse) {
+ if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
+ if (kLexan) GTEST_SKIP() << "Lexan doesn't support | in regexp.";
+
+ IntTable t;
+ // Start with 1 element so that `it` is never an end iterator.
+ t.insert(-1);
+ for (int i = 0; i < 10; ++i) {
+ auto it = t.begin();
+ t.insert(i);
+ EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
+ }
+}
+
+TEST(Table, InvalidIteratorUseWithReserve) {
+ if (!SwisstableGenerationsEnabled()) GTEST_SKIP() << "Generations disabled.";
+ if (kLexan) GTEST_SKIP() << "Lexan doesn't support | in regexp.";
+
+ IntTable t;
+ t.reserve(10);
+ t.insert(0);
+ auto it = t.begin();
+ // Reserved growth can't rehash.
+ for (int i = 1; i < 10; ++i) {
+ t.insert(i);
+ EXPECT_EQ(*it, 0);
+ }
+ // erase decreases size but does not decrease reserved growth so the next
+ // insertion still invalidates iterators.
+ t.erase(0);
+ // Unreserved growth can rehash.
+ t.insert(10);
+ EXPECT_DEATH_IF_SUPPORTED(*it, kInvalidIteratorDeathMessage);
+}
+
} // namespace
} // namespace container_internal
ABSL_NAMESPACE_END