diff options
-rw-r--r-- | absl/container/internal/raw_hash_set.h | 124 | ||||
-rw-r--r-- | absl/container/internal/raw_hash_set_test.cc | 33 | ||||
-rw-r--r-- | absl/debugging/symbolize_elf.inc | 10 | ||||
-rw-r--r-- | absl/hash/internal/hash.h | 3 |
4 files changed, 113 insertions, 57 deletions
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index 33e05736..bc33389b 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h @@ -179,6 +179,7 @@ #include <iterator> #include <limits> #include <memory> +#include <string> #include <tuple> #include <type_traits> #include <utility> @@ -1038,35 +1039,75 @@ size_t SelectBucketCountForIterRange(InputIter first, InputIter last, return 0; } -#define ABSL_INTERNAL_ASSERT_IS_FULL(ctrl, generation, generation_ptr, \ - operation) \ - do { \ - ABSL_HARDENING_ASSERT((ctrl != nullptr) && operation \ - " called on end() iterator."); \ - ABSL_HARDENING_ASSERT((ctrl != EmptyGroup()) && operation \ - " called on default-constructed iterator."); \ - if (SwisstableGenerationsEnabled() && generation != *generation_ptr) \ - ABSL_INTERNAL_LOG(FATAL, operation \ - " called on invalidated iterator. The table could " \ - "have rehashed since this iterator was initialized."); \ - ABSL_HARDENING_ASSERT( \ - (IsFull(*ctrl)) && operation \ - " called on invalid iterator. The element might have been erased or " \ - "the table might have rehashed."); \ - } while (0) +constexpr bool SwisstableDebugEnabled() { +#if defined(ABSL_SWISSTABLE_ENABLE_GENERATIONS) || \ + ABSL_OPTION_HARDENED == 1 || !defined(NDEBUG) + return true; +#else + return false; +#endif +} + +inline void AssertIsFull(const ctrl_t* ctrl, GenerationType generation, + const GenerationType* generation_ptr, + const char* operation) { + if (!SwisstableDebugEnabled()) return; + if (ctrl == nullptr) { + ABSL_INTERNAL_LOG(FATAL, + std::string(operation) + " called on end() iterator."); + } + if (ctrl == EmptyGroup()) { + ABSL_INTERNAL_LOG(FATAL, std::string(operation) + + " called on default-constructed iterator."); + } + if (SwisstableGenerationsEnabled()) { + if (generation != *generation_ptr) { + ABSL_INTERNAL_LOG(FATAL, + std::string(operation) + + " called on invalid iterator. The table could have " + "rehashed since this iterator was initialized."); + } + if (!IsFull(*ctrl)) { + ABSL_INTERNAL_LOG( + FATAL, + std::string(operation) + + " called on invalid iterator. The element was likely erased."); + } + } else { + if (!IsFull(*ctrl)) { + ABSL_INTERNAL_LOG( + FATAL, + std::string(operation) + + " called on invalid iterator. The element might have been erased " + "or the table might have rehashed. Consider running with " + "--config=asan to diagnose rehashing issues."); + } + } +} // Note that for comparisons, null/end iterators are valid. inline void AssertIsValidForComparison(const ctrl_t* ctrl, GenerationType generation, const GenerationType* generation_ptr) { - ABSL_HARDENING_ASSERT( - (ctrl == nullptr || ctrl == EmptyGroup() || IsFull(*ctrl)) && - "Invalid iterator comparison. The element might have " - "been erased or the table might have rehashed."); - if (SwisstableGenerationsEnabled() && generation != *generation_ptr) { - ABSL_INTERNAL_LOG(FATAL, - "Invalid iterator comparison. The table could have " - "rehashed since this iterator was initialized."); + if (!SwisstableDebugEnabled()) return; + const bool ctrl_is_valid_for_comparison = + ctrl == nullptr || ctrl == EmptyGroup() || IsFull(*ctrl); + if (SwisstableGenerationsEnabled()) { + if (generation != *generation_ptr) { + ABSL_INTERNAL_LOG(FATAL, + "Invalid iterator comparison. The table could have " + "rehashed since this iterator was initialized."); + } + if (!ctrl_is_valid_for_comparison) { + ABSL_INTERNAL_LOG( + FATAL, "Invalid iterator comparison. The element was likely erased."); + } + } else { + ABSL_HARDENING_ASSERT( + ctrl_is_valid_for_comparison && + "Invalid iterator comparison. The element might have been erased or " + "the table might have rehashed. Consider running with --config=asan to " + "diagnose rehashing issues."); } } @@ -1097,8 +1138,7 @@ inline void AssertSameContainer(const ctrl_t* ctrl_a, const ctrl_t* ctrl_b, const void* const& slot_b, const GenerationType* generation_ptr_a, const GenerationType* generation_ptr_b) { -#if defined(ABSL_SWISSTABLE_ENABLE_GENERATIONS) || \ - ABSL_OPTION_HARDENED == 1 || !defined(NDEBUG) + if (!SwisstableDebugEnabled()) return; const bool a_is_default = ctrl_a == EmptyGroup(); const bool b_is_default = ctrl_b == EmptyGroup(); if (a_is_default != b_is_default) { @@ -1108,9 +1148,9 @@ inline void AssertSameContainer(const ctrl_t* ctrl_a, const ctrl_t* ctrl_b, "with non-default-constructed iterator."); } if (a_is_default && b_is_default) return; -#endif - if (SwisstableGenerationsEnabled() && generation_ptr_a != generation_ptr_b) { + if (SwisstableGenerationsEnabled()) { + if (generation_ptr_a == generation_ptr_b) return; const bool a_is_empty = generation_ptr_a == EmptyGeneration(); const bool b_is_empty = generation_ptr_b == EmptyGeneration(); if (a_is_empty != b_is_empty) { @@ -1129,11 +1169,13 @@ inline void AssertSameContainer(const ctrl_t* ctrl_a, const ctrl_t* ctrl_b, ABSL_INTERNAL_LOG(FATAL, "Invalid iterator comparison. Comparing non-end() " "iterators from different hashtables."); + } else { + ABSL_HARDENING_ASSERT( + AreItersFromSameContainer(ctrl_a, ctrl_b, slot_a, slot_b) && + "Invalid iterator comparison. The iterators may be from different " + "containers or the container might have rehashed. Consider running " + "with --config=asan to diagnose rehashing issues."); } - ABSL_HARDENING_ASSERT( - AreItersFromSameContainer(ctrl_a, ctrl_b, slot_a, slot_b) && - "Invalid iterator comparison. The iterators may be from different " - "containers or the container might have rehashed."); } struct FindInfo { @@ -1471,22 +1513,19 @@ class raw_hash_set { // PRECONDITION: not an end() iterator. reference operator*() const { - ABSL_INTERNAL_ASSERT_IS_FULL(ctrl_, generation(), generation_ptr(), - "operator*()"); + AssertIsFull(ctrl_, generation(), generation_ptr(), "operator*()"); return PolicyTraits::element(slot_); } // PRECONDITION: not an end() iterator. pointer operator->() const { - ABSL_INTERNAL_ASSERT_IS_FULL(ctrl_, generation(), generation_ptr(), - "operator->"); + AssertIsFull(ctrl_, generation(), generation_ptr(), "operator->"); return &operator*(); } // PRECONDITION: not an end() iterator. iterator& operator++() { - ABSL_INTERNAL_ASSERT_IS_FULL(ctrl_, generation(), generation_ptr(), - "operator++"); + AssertIsFull(ctrl_, generation(), generation_ptr(), "operator++"); ++ctrl_; ++slot_; skip_empty_or_deleted(); @@ -2052,8 +2091,7 @@ class raw_hash_set { // This overload is necessary because otherwise erase<K>(const K&) would be // a better match if non-const iterator is passed as an argument. void erase(iterator it) { - ABSL_INTERNAL_ASSERT_IS_FULL(it.ctrl_, it.generation(), it.generation_ptr(), - "erase()"); + AssertIsFull(it.ctrl_, it.generation(), it.generation_ptr(), "erase()"); PolicyTraits::destroy(&alloc_ref(), it.slot_); erase_meta_only(it); } @@ -2087,9 +2125,8 @@ class raw_hash_set { } node_type extract(const_iterator position) { - ABSL_INTERNAL_ASSERT_IS_FULL(position.inner_.ctrl_, - position.inner_.generation(), - position.inner_.generation_ptr(), "extract()"); + AssertIsFull(position.inner_.ctrl_, position.inner_.generation(), + position.inner_.generation_ptr(), "extract()"); auto node = CommonAccess::Transfer<node_type>(alloc_ref(), position.inner_.slot_); erase_meta_only(position); @@ -2739,6 +2776,5 @@ ABSL_NAMESPACE_END } // namespace absl #undef ABSL_SWISSTABLE_ENABLE_GENERATIONS -#undef ABSL_INTERNAL_ASSERT_IS_FULL #endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_ diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index 4f2d006d..c13b6757 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc @@ -2056,7 +2056,8 @@ bool IsAssertEnabled() { } TEST(TableDeathTest, InvalidIteratorAsserts) { - if (!IsAssertEnabled()) GTEST_SKIP() << "Assertions not enabled."; + if (!IsAssertEnabled() && !SwisstableGenerationsEnabled()) + GTEST_SKIP() << "Assertions not enabled."; IntTable t; // Extra simple "regexp" as regexp support is highly varied across platforms. @@ -2068,9 +2069,12 @@ TEST(TableDeathTest, InvalidIteratorAsserts) { t.insert(0); iter = t.begin(); t.erase(iter); - EXPECT_DEATH_IF_SUPPORTED(++iter, - "operator.* called on invalid iterator. The " - "element might have been erased"); + const char* const kErasedDeathMessage = + SwisstableGenerationsEnabled() + ? "operator.* called on invalid iterator.*was likely erased" + : "operator.* called on invalid iterator.*might have been " + "erased.*config=asan"; + EXPECT_DEATH_IF_SUPPORTED(++iter, kErasedDeathMessage); } // Invalid iterator use can trigger heap-use-after-free in asan, @@ -2087,7 +2091,8 @@ constexpr bool kMsvc = false; #endif TEST(TableDeathTest, IteratorInvalidAssertsEqualityOperator) { - if (!IsAssertEnabled()) GTEST_SKIP() << "Assertions not enabled."; + if (!IsAssertEnabled() && !SwisstableGenerationsEnabled()) + GTEST_SKIP() << "Assertions not enabled."; IntTable t; t.insert(1); @@ -2100,8 +2105,9 @@ TEST(TableDeathTest, IteratorInvalidAssertsEqualityOperator) { t.erase(iter1); // Extra simple "regexp" as regexp support is highly varied across platforms. const char* const kErasedDeathMessage = - "Invalid iterator comparison. The element might have .*been erased or " - "the table might have rehashed."; + SwisstableGenerationsEnabled() + ? "Invalid iterator comparison.*was likely erased" + : "Invalid iterator comparison.*might have been erased.*config=asan"; EXPECT_DEATH_IF_SUPPORTED(void(iter1 == iter2), kErasedDeathMessage); EXPECT_DEATH_IF_SUPPORTED(void(iter2 != iter1), kErasedDeathMessage); t.erase(iter2); @@ -2114,17 +2120,20 @@ TEST(TableDeathTest, IteratorInvalidAssertsEqualityOperator) { iter2 = t2.begin(); const char* const kContainerDiffDeathMessage = SwisstableGenerationsEnabled() - ? "Invalid iterator comparison.*non-end" - : "Invalid iterator comparison. The iterators may be from different " - ".*containers or the container might have rehashed."; + ? "Invalid iterator comparison.*iterators from different hashtables" + : "Invalid iterator comparison.*may be from different " + ".*containers.*config=asan"; EXPECT_DEATH_IF_SUPPORTED(void(iter1 == iter2), kContainerDiffDeathMessage); EXPECT_DEATH_IF_SUPPORTED(void(iter2 == iter1), kContainerDiffDeathMessage); for (int i = 0; i < 10; ++i) t1.insert(i); // There should have been a rehash in t1. if (kMsvc) return; // MSVC doesn't support | in regex. - EXPECT_DEATH_IF_SUPPORTED(void(iter1 == t1.begin()), - kInvalidIteratorDeathMessage); + const char* const kRehashedDeathMessage = + SwisstableGenerationsEnabled() + ? kInvalidIteratorDeathMessage + : "Invalid iterator comparison.*might have rehashed.*config=asan"; + EXPECT_DEATH_IF_SUPPORTED(void(iter1 == t1.begin()), kRehashedDeathMessage); } #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc index ffb4eecf..0fee89f2 100644 --- a/absl/debugging/symbolize_elf.inc +++ b/absl/debugging/symbolize_elf.inc @@ -532,6 +532,11 @@ bool ForEachSection(int fd, return false; } + // Technically it can be larger, but in practice this never happens. + if (elf_header.e_shentsize != sizeof(ElfW(Shdr))) { + return false; + } + ElfW(Shdr) shstrtab; off_t shstrtab_offset = static_cast<off_t>(elf_header.e_shoff) + elf_header.e_shentsize * elf_header.e_shstrndx; @@ -584,6 +589,11 @@ bool GetSectionHeaderByName(int fd, const char *name, size_t name_len, return false; } + // Technically it can be larger, but in practice this never happens. + if (elf_header.e_shentsize != sizeof(ElfW(Shdr))) { + return false; + } + ElfW(Shdr) shstrtab; off_t shstrtab_offset = static_cast<off_t>(elf_header.e_shoff) + elf_header.e_shentsize * elf_header.e_shstrndx; diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h index f81b81bf..89740dab 100644 --- a/absl/hash/internal/hash.h +++ b/absl/hash/internal/hash.h @@ -1136,7 +1136,8 @@ class ABSL_DLL MixingHashState : public HashStateBase<MixingHashState> { // probably per-build and not per-process. ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Seed() { #if (!defined(__clang__) || __clang_major__ > 11) && \ - (!defined(__apple_build_version__) || __apple_build_version__ >= 19558921) // Xcode 12 + (!defined(__apple_build_version__) || \ + __apple_build_version__ >= 19558921) // Xcode 12 return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&kSeed)); #else // Workaround the absence of |