Commit 17c1a5e8 by Evan Brown Committed by Copybara-Service

Add validation against use of destroyed hash tables.

PiperOrigin-RevId: 663373500
Change-Id: I6b2014f8cc4244e1599c907197cfaadb6739f72b
parent b2665cee
...@@ -540,8 +540,8 @@ ABSL_DLL extern const ctrl_t kEmptyGroup[32]; ...@@ -540,8 +540,8 @@ ABSL_DLL extern const ctrl_t kEmptyGroup[32];
// classes of bugs. // classes of bugs.
enum InvalidCapacity : size_t { enum InvalidCapacity : size_t {
kAboveMaxValidCapacity = ~size_t{} - 100, kAboveMaxValidCapacity = ~size_t{} - 100,
// Used for reentrancy assertions. kReentrance,
kInvalidReentrance, kDestroyed,
}; };
// Returns a pointer to a control byte group that can be used by empty tables. // Returns a pointer to a control byte group that can be used by empty tables.
...@@ -1462,7 +1462,7 @@ class CommonFields : public CommonFieldsGenerationInfo { ...@@ -1462,7 +1462,7 @@ class CommonFields : public CommonFieldsGenerationInfo {
return; return;
#endif #endif
const size_t cap = capacity(); const size_t cap = capacity();
set_capacity(kInvalidReentrance); set_capacity(InvalidCapacity::kReentrance);
f(); f();
set_capacity(cap); set_capacity(cap);
} }
...@@ -2858,7 +2858,12 @@ class raw_hash_set { ...@@ -2858,7 +2858,12 @@ class raw_hash_set {
typename AllocTraits::propagate_on_container_move_assignment()); typename AllocTraits::propagate_on_container_move_assignment());
} }
~raw_hash_set() { destructor_impl(); } ~raw_hash_set() {
destructor_impl();
#ifndef NDEBUG
common().set_capacity(InvalidCapacity::kDestroyed);
#endif
}
iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND {
if (ABSL_PREDICT_FALSE(empty())) return end(); if (ABSL_PREDICT_FALSE(empty())) return end();
...@@ -3875,11 +3880,13 @@ class raw_hash_set { ...@@ -3875,11 +3880,13 @@ class raw_hash_set {
} }
// Asserts that the capacity is not a sentinel invalid value. // Asserts that the capacity is not a sentinel invalid value.
// TODO(b/296061262): also add asserts for moved-from and destroyed states. // TODO(b/296061262): also add asserts for moved-from state.
void AssertNotDebugCapacity() const { void AssertNotDebugCapacity() const {
assert(capacity() != kInvalidReentrance && assert(capacity() != InvalidCapacity::kReentrance &&
"reentrant container access during element construction/destruction " "reentrant container access during element construction/destruction "
"is not allowed."); "is not allowed.");
assert(capacity() != InvalidCapacity::kDestroyed &&
"use of destroyed hash table.");
} }
// Asserts that hash and equal functors provided by the user are consistent, // Asserts that hash and equal functors provided by the user are consistent,
......
...@@ -3661,6 +3661,19 @@ TEST(Table, ReentrantCallsFail) { ...@@ -3661,6 +3661,19 @@ TEST(Table, ReentrantCallsFail) {
#endif #endif
} }
TEST(Table, DestroyedCallsFail) {
#ifdef NDEBUG
GTEST_SKIP() << "Destroyed checks only enabled in debug mode.";
#else
absl::optional<IntTable> t;
t.emplace({1});
IntTable* t_ptr = &*t;
EXPECT_TRUE(t_ptr->contains(1));
t.reset();
EXPECT_DEATH_IF_SUPPORTED(t_ptr->contains(1), "");
#endif
}
} // namespace } // namespace
} // namespace container_internal } // namespace container_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment