summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--absl/synchronization/internal/graphcycles.cc11
-rw-r--r--absl/synchronization/internal/graphcycles.h5
-rw-r--r--absl/synchronization/internal/graphcycles_test.cc19
3 files changed, 34 insertions, 1 deletions
diff --git a/absl/synchronization/internal/graphcycles.cc b/absl/synchronization/internal/graphcycles.cc
index 61b4ec05..129067c1 100644
--- a/absl/synchronization/internal/graphcycles.cc
+++ b/absl/synchronization/internal/graphcycles.cc
@@ -211,7 +211,7 @@ class NodeSet {
Vec<int32_t> table_;
uint32_t occupied_; // Count of non-empty slots (includes deleted slots)
- static uint32_t Hash(int32_t a) { return static_cast<uint32_t>(a * 41); }
+ static uint32_t Hash(int32_t a) { return static_cast<uint32_t>(a) * 41; }
// Return index for storing v. May return an empty index or deleted index
uint32_t FindIndex(int32_t v) const {
@@ -365,6 +365,14 @@ static Node* FindNode(GraphCycles::Rep* rep, GraphId id) {
return (n->version == NodeVersion(id)) ? n : nullptr;
}
+void GraphCycles::TestOnlyAddNodes(uint32_t n) {
+ uint32_t old_size = rep_->nodes_.size();
+ rep_->nodes_.resize(n);
+ for (auto i = old_size; i < n; ++i) {
+ rep_->nodes_[i] = nullptr;
+ }
+}
+
GraphCycles::GraphCycles() {
InitArenaIfNecessary();
rep_ = new (base_internal::LowLevelAlloc::AllocWithArena(sizeof(Rep), arena))
@@ -373,6 +381,7 @@ GraphCycles::GraphCycles() {
GraphCycles::~GraphCycles() {
for (auto* node : rep_->nodes_) {
+ if (node == nullptr) { continue; }
node->Node::~Node();
base_internal::LowLevelAlloc::Free(node);
}
diff --git a/absl/synchronization/internal/graphcycles.h b/absl/synchronization/internal/graphcycles.h
index ceba33e4..08f304bc 100644
--- a/absl/synchronization/internal/graphcycles.h
+++ b/absl/synchronization/internal/graphcycles.h
@@ -126,6 +126,11 @@ class GraphCycles {
// Expensive: should only be called from graphcycles_test.cc.
bool CheckInvariants() const;
+ // Test-only method to add more nodes. The nodes will not be valid, and this
+ // method should only be used to test the behavior of the graph when it is
+ // very full.
+ void TestOnlyAddNodes(uint32_t n);
+
// ----------------------------------------------------
struct Rep;
private:
diff --git a/absl/synchronization/internal/graphcycles_test.cc b/absl/synchronization/internal/graphcycles_test.cc
index 3c6ef798..47410aad 100644
--- a/absl/synchronization/internal/graphcycles_test.cc
+++ b/absl/synchronization/internal/graphcycles_test.cc
@@ -14,6 +14,7 @@
#include "absl/synchronization/internal/graphcycles.h"
+#include <climits>
#include <map>
#include <random>
#include <unordered_set>
@@ -458,6 +459,24 @@ TEST_F(GraphCyclesTest, ManyEdges) {
CheckInvariants(g_);
}
+TEST(GraphCycles, IntegerOverflow) {
+ GraphCycles graph_cycles;
+ char *buf = (char *)nullptr;
+ GraphId prev_id = graph_cycles.GetId(buf);
+ buf += 1;
+ GraphId id = graph_cycles.GetId(buf);
+ ASSERT_TRUE(graph_cycles.InsertEdge(prev_id, id));
+
+ // INT_MAX / 40 is enough to cause an overflow when multiplied by 41.
+ graph_cycles.TestOnlyAddNodes(INT_MAX / 40);
+
+ buf += 1;
+ GraphId newid = graph_cycles.GetId(buf);
+ graph_cycles.HasEdge(prev_id, newid);
+
+ graph_cycles.RemoveNode(buf);
+}
+
} // namespace synchronization_internal
ABSL_NAMESPACE_END
} // namespace absl