diff options
author | Evan Brown <ezb@google.com> | 2022-12-19 11:53:21 -0800 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2022-12-19 11:54:08 -0800 |
commit | a1ec5d62e70994d4d488d827f4e44a9a4165fd36 (patch) | |
tree | 1c8e0e5b8d8a351f50005da33254a6531b98882e /absl/container/internal/raw_hash_set_test.cc | |
parent | dbc61b490c5c259df33af59f9922a7224341397b (diff) | |
download | abseil-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.cc | 96 |
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 |