Skip to content

Commit 688c8a1

Browse files
committed
check for overflow when computing total node weight
1 parent 1e1b48c commit 688c8a1

6 files changed

Lines changed: 51 additions & 4 deletions

File tree

mt-kahypar/datastructures/hypergraph_common.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,19 @@ using RatingType = double;
4545
#define ID(X) static_cast<uint64_t>(X)
4646
using HypernodeID = uint64_t;
4747
using HyperedgeID = uint64_t;
48+
using HypernodeWeight = int64_t;
49+
using HyperedgeWeight = int64_t;
4850
// louvain graph
4951
using NodeID = uint64_t;
5052
#else
5153
#define ID(X) static_cast<uint32_t>(X)
5254
using HypernodeID = uint32_t;
5355
using HyperedgeID = uint32_t;
56+
using HypernodeWeight = int32_t;
57+
using HyperedgeWeight = int32_t;
5458
// louvain graph
5559
using NodeID = uint32_t;
5660
#endif
57-
using HypernodeWeight = int32_t;
58-
using HyperedgeWeight = int32_t;
5961
using PartitionID = int32_t;
6062
using Gain = HyperedgeWeight;
6163

mt-kahypar/datastructures/hypergraph_utils.h

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,32 @@
2828

2929
#include "mt-kahypar/datastructures/hypergraph_common.h"
3030

31+
#include <limits>
32+
3133
#include <tbb/parallel_reduce.h>
3234

3335

3436
namespace mt_kahypar {
3537

38+
namespace impl {
39+
inline HypernodeWeight add(HypernodeWeight lhs, HypernodeWeight rhs) {
40+
if (lhs > std::numeric_limits<HypernodeWeight>::max() - rhs) {
41+
std::string msg = "total node weight overflows weight data type";
42+
if constexpr (sizeof(HypernodeWeight) < 8) {
43+
msg += " (build with -DKAHYPAR_USE_64_BIT_IDS=ON to support larger ranges)";
44+
}
45+
throw InvalidInputException(msg);
46+
}
47+
return lhs + rhs;
48+
}
49+
50+
struct safe_addition {
51+
HypernodeWeight operator()(const HypernodeWeight& lhs, const HypernodeWeight& rhs) const {
52+
return add(lhs, rhs);
53+
}
54+
};
55+
}
56+
3657
template<typename Hypergraph>
3758
HypernodeWeight computeTotalNodeWeightParallel(const Hypergraph& hypergraph, const HypernodeID num_hypernodes) {
3859
return tbb::parallel_reduce(
@@ -41,11 +62,11 @@ HypernodeWeight computeTotalNodeWeightParallel(const Hypergraph& hypergraph, con
4162
HypernodeWeight weight = init;
4263
for (HypernodeID hn = range.begin(); hn < range.end(); ++hn) {
4364
if (hypergraph.nodeIsEnabled(hn)) {
44-
weight += hypergraph.nodeWeight(hn);
65+
weight = impl::add(weight, hypergraph.nodeWeight(hn));
4566
}
4667
}
4768
return weight;
48-
}, std::plus<>());
69+
}, impl::safe_addition{});
4970
}
5071

5172
} // namespace mt_kahypar

tests/datastructures/dynamic_graph_test.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,12 @@ TEST_F(ADynamicGraph, VerifiesEdgeSizes) {
180180
}
181181
}
182182

183+
TEST_F(ADynamicGraph, PreventsWeightOverflow) {
184+
hypergraph.setNodeWeight(0, std::numeric_limits<HypernodeWeight>::max() / 2);
185+
hypergraph.setNodeWeight(1, std::numeric_limits<HypernodeWeight>::max() / 2);
186+
ASSERT_THROW(hypergraph.computeAndSetTotalNodeWeight(parallel_tag_t()), InvalidInputException);
187+
}
188+
183189
TEST_F(ADynamicGraph, SetsCommunityIDsForEachVertex) {
184190
hypergraph.setCommunityID(0, 1);
185191
hypergraph.setCommunityID(1, 1);

tests/datastructures/dynamic_hypergraph_test.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,12 @@ TEST_F(ADynamicHypergraph, VerifiesEdgeSizes) {
196196
ASSERT_EQ(3, hypergraph.edgeSize(3));
197197
}
198198

199+
TEST_F(ADynamicHypergraph, PreventsWeightOverflow) {
200+
hypergraph.setNodeWeight(0, std::numeric_limits<HypernodeWeight>::max() / 2);
201+
hypergraph.setNodeWeight(1, std::numeric_limits<HypernodeWeight>::max() / 2);
202+
ASSERT_THROW(hypergraph.computeAndSetTotalNodeWeight(parallel_tag_t()), InvalidInputException);
203+
}
204+
199205
TEST_F(ADynamicHypergraph, SetsCommunityIDsForEachVertex) {
200206
hypergraph.setCommunityID(0, 1);
201207
hypergraph.setCommunityID(1, 1);

tests/datastructures/static_graph_test.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@ TEST_F(AStaticGraph, VerifiesEdgeSizes) {
173173
}
174174
}
175175

176+
TEST_F(AStaticGraph, PreventsWeightOverflow) {
177+
hypergraph.setNodeWeight(0, std::numeric_limits<HypernodeWeight>::max() / 2);
178+
hypergraph.setNodeWeight(1, std::numeric_limits<HypernodeWeight>::max() / 2);
179+
ASSERT_THROW(hypergraph.computeAndSetTotalNodeWeight(parallel_tag_t()), InvalidInputException);
180+
}
181+
176182
TEST_F(AStaticGraph, SetsCommunityIDsForEachVertex) {
177183
hypergraph.setCommunityID(0, 1);
178184
hypergraph.setCommunityID(1, 1);

tests/datastructures/static_hypergraph_test.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,12 @@ TEST_F(AStaticHypergraph, VerifiesEdgeSizes) {
181181
ASSERT_EQ(3, hypergraph.edgeSize(3));
182182
}
183183

184+
TEST_F(AStaticHypergraph, PreventsWeightOverflow) {
185+
hypergraph.setNodeWeight(0, std::numeric_limits<HypernodeWeight>::max() / 2);
186+
hypergraph.setNodeWeight(1, std::numeric_limits<HypernodeWeight>::max() / 2);
187+
ASSERT_THROW(hypergraph.computeAndSetTotalNodeWeight(parallel_tag_t()), InvalidInputException);
188+
}
189+
184190
TEST_F(AStaticHypergraph, SetsCommunityIDsForEachVertex) {
185191
hypergraph.setCommunityID(0, 1);
186192
hypergraph.setCommunityID(1, 1);

0 commit comments

Comments
 (0)