Commit 90184f6c by Evan Brown Committed by Copybara-Service

Improve b-tree error messages when dereferencing invalid iterators.

- Check for invalid generation before checking for other types of invalid iterators.
- Check specifically for dereferencing end() iterators.

PiperOrigin-RevId: 483725646
Change-Id: Ibca19c48b1b242384683580145be8fb9ae707bc8
parent b3e64c41
...@@ -3340,6 +3340,14 @@ TEST(Btree, IteratorSubtraction) { ...@@ -3340,6 +3340,14 @@ TEST(Btree, IteratorSubtraction) {
} }
} }
#ifndef NDEBUG
TEST(Btree, DereferencingEndIterator) {
absl::btree_set<int> set;
for (int i = 0; i < 1000; ++i) set.insert(i);
EXPECT_DEATH(*set.end(), R"regex(Dereferencing end\(\) iterator)regex");
}
#endif
} // namespace } // namespace
} // namespace container_internal } // namespace container_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
......
...@@ -1098,9 +1098,12 @@ class btree_iterator { ...@@ -1098,9 +1098,12 @@ class btree_iterator {
// Accessors for the key/value the iterator is pointing at. // Accessors for the key/value the iterator is pointing at.
reference operator*() const { reference operator*() const {
ABSL_HARDENING_ASSERT(node_ != nullptr); ABSL_HARDENING_ASSERT(node_ != nullptr);
ABSL_HARDENING_ASSERT(node_->start() <= position_);
ABSL_HARDENING_ASSERT(node_->finish() > position_);
assert_valid_generation(); assert_valid_generation();
ABSL_HARDENING_ASSERT(position_ >= node_->start());
if (position_ >= node_->finish()) {
ABSL_HARDENING_ASSERT(!IsEndIterator() && "Dereferencing end() iterator");
ABSL_HARDENING_ASSERT(position_ < node_->finish());
}
return node_->value(static_cast<field_type>(position_)); return node_->value(static_cast<field_type>(position_));
} }
pointer operator->() const { return &operator*(); } pointer operator->() const { return &operator*(); }
...@@ -1158,6 +1161,15 @@ class btree_iterator { ...@@ -1158,6 +1161,15 @@ class btree_iterator {
#endif #endif
} }
bool IsEndIterator() const {
if (position_ != node_->finish()) return false;
// Navigate to the rightmost node.
node_type *node = node_;
while (!node->is_root()) node = node->parent();
while (node->is_internal()) node = node->child(node->finish());
return node == node_;
}
// Returns n such that n calls to ++other yields *this. // Returns n such that n calls to ++other yields *this.
// Precondition: n exists && (this->node_ != other.node_ || // Precondition: n exists && (this->node_ != other.node_ ||
// !this->node_->is_leaf() || this->position_ != other.position_). // !this->node_->is_leaf() || this->position_ != other.position_).
......
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