Skip to content

Commit cb0a264

Browse files
committed
input validation: add overflow checks to library interfaces
also adds according tests for the C interface
1 parent 1ce3b2f commit cb0a264

3 files changed

Lines changed: 89 additions & 13 deletions

File tree

include/lib_helper_functions.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#pragma once
2828

2929
#include <chrono>
30+
#include <limits>
3031
#include <string>
3132
#include <sstream>
3233
#include <type_traits>
@@ -133,6 +134,17 @@ bool is_compatible(mt_kahypar_partitioned_hypergraph_t partitioned_hg, mt_kahypa
133134
return false;
134135
}
135136

137+
template<typename OutType, typename InType>
138+
void check_overflow(const InType& value, const char* what) {
139+
if (value > static_cast<InType>(std::numeric_limits<OutType>::max())) {
140+
std::string msg = std::string(what) + " overflows input range of internal data type: " + STR(value);
141+
if constexpr (sizeof(OutType) < 8) {
142+
msg += " (build with -DKAHYPAR_USE_64_BIT_IDS=ON to support larger ID ranges)";
143+
}
144+
throw InvalidInputException(msg);
145+
}
146+
}
147+
136148
void check_if_all_relevant_parameters_are_set(Context& context) {
137149
bool success = true;
138150
auto check_parameter = [&](bool is_uninitialized, const char* warning_msg) {
@@ -302,6 +314,9 @@ mt_kahypar_hypergraph_t create_hypergraph(const Context& context,
302314
const vec<vec<HypernodeID>>& edge_vector,
303315
const mt_kahypar_hyperedge_weight_t* hyperedge_weights,
304316
const mt_kahypar_hypernode_weight_t* vertex_weights) {
317+
check_overflow<HypernodeID>(num_vertices, "number of vertices");
318+
check_overflow<HyperedgeID>(num_hyperedges, "number of hyperedges");
319+
305320
switch ( context.partition.preset_type ) {
306321
case PresetType::deterministic:
307322
case PresetType::deterministic_quality:
@@ -327,9 +342,11 @@ mt_kahypar_hypergraph_t create_hypergraph_from_adjacency_array(const Context& co
327342
const mt_kahypar_hypernode_id_t num_vertices,
328343
const mt_kahypar_hyperedge_id_t num_hyperedges,
329344
const size_t* hyperedge_indices,
330-
const mt_kahypar_hyperedge_id_t* hyperedges,
345+
const mt_kahypar_hypernode_id_t* hyperedges,
331346
const mt_kahypar_hyperedge_weight_t* hyperedge_weights,
332347
const mt_kahypar_hypernode_weight_t* vertex_weights) {
348+
check_overflow<HypernodeID>(num_vertices, "number of vertices");
349+
check_overflow<HyperedgeID>(num_hyperedges, "number of hyperedges");
333350
if (hyperedge_indices[0] != 0) {
334351
throw InvalidInputException("First entry in hyperedge indices must be 0, but is: " + STR(hyperedge_indices[0]));
335352
}
@@ -350,7 +367,9 @@ mt_kahypar_hypergraph_t create_hypergraph_from_adjacency_array(const Context& co
350367
const size_t num_pins = hyperedge_indices[he + 1] - hyperedge_indices[he];
351368
edge_vector[he].resize(num_pins);
352369
for ( size_t i = 0; i < num_pins; ++i ) {
353-
edge_vector[he][i] = hyperedges[hyperedge_indices[he] + i];
370+
mt_kahypar_hypernode_id_t pin = hyperedges[hyperedge_indices[he] + i];
371+
check_overflow<HypernodeID>(pin, "pin");
372+
edge_vector[he][i] = pin;
354373
}
355374

356375
utils::deduplicateHyperedgePins(edge_vector[he], num_duplicated_pins, num_hes_with_duplicated_pins);
@@ -368,6 +387,9 @@ mt_kahypar_hypergraph_t create_graph(const Context& context,
368387
const vec<std::pair<HypernodeID, HypernodeID>>& edge_vector,
369388
const mt_kahypar_hyperedge_weight_t* edge_weights,
370389
const mt_kahypar_hypernode_weight_t* vertex_weights) {
390+
check_overflow<HypernodeID>(num_vertices, "number of nodes");
391+
check_overflow<HyperedgeID>(num_edges, "number of edges");
392+
371393
switch ( context.partition.preset_type ) {
372394
case PresetType::deterministic:
373395
case PresetType::deterministic_quality:

lib/mtkahypar.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,12 +336,14 @@ mt_kahypar_hypergraph_t mt_kahypar_create_graph(const mt_kahypar_context_t* cont
336336
mt_kahypar_error_t* error) {
337337
// Transform adjacence array into adjacence list
338338
vec<std::pair<mt_kahypar::HypernodeID, mt_kahypar::HypernodeID>> edge_vector(num_edges);
339-
tbb::parallel_for<mt_kahypar::HyperedgeID>(0, num_edges, [&](const mt_kahypar::HyperedgeID& he) {
340-
edge_vector[he] = std::make_pair(edges[2*he], edges[2*he + 1]);
341-
});
342339

343340
const Context& c = *reinterpret_cast<const Context*>(context);
344341
try {
342+
tbb::parallel_for<mt_kahypar::HyperedgeID>(0, num_edges, [&](const mt_kahypar::HyperedgeID& he) {
343+
lib::check_overflow<HypernodeID>(edges[2*he], "endpoint of edge");
344+
lib::check_overflow<HypernodeID>(edges[2*he + 1], "endpoint of edge");
345+
edge_vector[he] = std::make_pair(edges[2*he], edges[2*he + 1]);
346+
});
345347
return lib::create_graph(c, num_vertices, num_edges, edge_vector, edge_weights, vertex_weights);
346348
} catch ( std::exception& ex ) {
347349
*error = to_error(ex);

tests/interface/interface_test.cc

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ namespace mt_kahypar {
167167
TEST(MtKaHyPar, StaticHypergraphConstructionHandlesErrors) {
168168
mt_kahypar_error_t error;
169169
mt_kahypar_context_t* context = mt_kahypar_context_from_preset(DEFAULT);
170-
const mt_kahypar_hypernode_id_t num_vertices = 7;
171-
const mt_kahypar_hyperedge_id_t num_hyperedges = 4;
170+
mt_kahypar_hypernode_id_t num_vertices = 7;
171+
mt_kahypar_hyperedge_id_t num_hyperedges = 4;
172172

173173
std::unique_ptr<size_t[]> hyperedge_indices = std::make_unique<size_t[]>(5);
174174
hyperedge_indices[0] = 0; hyperedge_indices[1] = 2; hyperedge_indices[2] = 6;
@@ -210,6 +210,23 @@ namespace mt_kahypar {
210210
attempt_construction("giant HE");
211211
hyperedge_indices[4] = 12;
212212

213+
if constexpr (sizeof(HypernodeID) < 8) {
214+
hyperedges[3] = static_cast<mt_kahypar_hypernode_id_t>(std::numeric_limits<HypernodeID>::max()) + 1;
215+
attempt_construction("overflow pin");
216+
hyperedges[3] = 1;
217+
218+
hyperedge_indices[4] = static_cast<mt_kahypar_hypernode_id_t>(std::numeric_limits<HypernodeID>::max()) + 13;
219+
attempt_construction("overflow HE index");
220+
hyperedge_indices[4] = 12;
221+
222+
num_vertices = static_cast<mt_kahypar_hypernode_id_t>(std::numeric_limits<HypernodeID>::max()) + 8;
223+
attempt_construction("overflow num vertices");
224+
num_vertices = 7;
225+
226+
num_hyperedges = static_cast<mt_kahypar_hyperedge_id_t>(std::numeric_limits<HyperedgeID>::max()) + 5;
227+
attempt_construction("overflow num hyperedges");
228+
}
229+
213230
mt_kahypar_free_hypergraph(hypergraph);
214231
}
215232

@@ -245,8 +262,8 @@ namespace mt_kahypar {
245262
TEST(MtKaHyPar, DynamicHypergraphConstructionHandlesErrors) {
246263
mt_kahypar_error_t error;
247264
mt_kahypar_context_t* context = mt_kahypar_context_from_preset(HIGHEST_QUALITY);
248-
const mt_kahypar_hypernode_id_t num_vertices = 7;
249-
const mt_kahypar_hyperedge_id_t num_hyperedges = 4;
265+
mt_kahypar_hypernode_id_t num_vertices = 7;
266+
mt_kahypar_hyperedge_id_t num_hyperedges = 4;
250267

251268
std::unique_ptr<size_t[]> hyperedge_indices = std::make_unique<size_t[]>(5);
252269
hyperedge_indices[0] = 0; hyperedge_indices[1] = 2; hyperedge_indices[2] = 6;
@@ -288,6 +305,23 @@ namespace mt_kahypar {
288305
attempt_construction("giant HE");
289306
hyperedge_indices[4] = 12;
290307

308+
if constexpr (sizeof(HypernodeID) < 8) {
309+
hyperedges[3] = static_cast<mt_kahypar_hypernode_id_t>(std::numeric_limits<HypernodeID>::max()) + 1;
310+
attempt_construction("overflow pin");
311+
hyperedges[3] = 1;
312+
313+
hyperedge_indices[4] = static_cast<mt_kahypar_hypernode_id_t>(std::numeric_limits<HypernodeID>::max()) + 13;
314+
attempt_construction("overflow HE index");
315+
hyperedge_indices[4] = 12;
316+
317+
num_vertices = static_cast<mt_kahypar_hypernode_id_t>(std::numeric_limits<HypernodeID>::max()) + 8;
318+
attempt_construction("overflow num vertices");
319+
num_vertices = 7;
320+
321+
num_hyperedges = static_cast<mt_kahypar_hyperedge_id_t>(std::numeric_limits<HyperedgeID>::max()) + 5;
322+
attempt_construction("overflow num hyperedges");
323+
}
324+
291325
mt_kahypar_free_hypergraph(hypergraph);
292326
}
293327

@@ -320,8 +354,8 @@ namespace mt_kahypar {
320354
TEST(MtKaHyPar, StaticGraphConstructionHandlesErrors) {
321355
mt_kahypar_error_t error;
322356
mt_kahypar_context_t* context = mt_kahypar_context_from_preset(DEFAULT);
323-
const mt_kahypar_hypernode_id_t num_vertices = 5;
324-
const mt_kahypar_hyperedge_id_t num_hyperedges = 6;
357+
mt_kahypar_hypernode_id_t num_vertices = 5;
358+
mt_kahypar_hyperedge_id_t num_hyperedges = 6;
325359

326360
std::unique_ptr<mt_kahypar_hypernode_id_t[]> edges =
327361
std::make_unique<mt_kahypar_hypernode_id_t[]>(12);
@@ -347,6 +381,15 @@ namespace mt_kahypar {
347381
edges[2] = 2;
348382
attempt_construction("self loop");
349383

384+
if constexpr (sizeof(HypernodeID) < 8) {
385+
edges[2] = static_cast<mt_kahypar_hypernode_id_t>(std::numeric_limits<HypernodeID>::max()) + 1;
386+
attempt_construction("overflow node ID");
387+
edges[2] = 0;
388+
389+
num_vertices = static_cast<mt_kahypar_hypernode_id_t>(std::numeric_limits<HypernodeID>::max()) + 6;
390+
attempt_construction("overflow num nodes");
391+
}
392+
350393
mt_kahypar_free_hypergraph(graph);
351394
}
352395

@@ -379,8 +422,8 @@ namespace mt_kahypar {
379422
TEST(MtKaHyPar, DynamicGraphConstructionHandlesErrors) {
380423
mt_kahypar_error_t error;
381424
mt_kahypar_context_t* context = mt_kahypar_context_from_preset(HIGHEST_QUALITY);
382-
const mt_kahypar_hypernode_id_t num_vertices = 5;
383-
const mt_kahypar_hyperedge_id_t num_hyperedges = 6;
425+
mt_kahypar_hypernode_id_t num_vertices = 5;
426+
mt_kahypar_hyperedge_id_t num_hyperedges = 6;
384427

385428
std::unique_ptr<mt_kahypar_hypernode_id_t[]> edges =
386429
std::make_unique<mt_kahypar_hypernode_id_t[]>(12);
@@ -406,6 +449,15 @@ namespace mt_kahypar {
406449
edges[2] = 2;
407450
attempt_construction("self loop");
408451

452+
if constexpr (sizeof(HypernodeID) < 8) {
453+
edges[2] = static_cast<mt_kahypar_hypernode_id_t>(std::numeric_limits<HypernodeID>::max()) + 1;
454+
attempt_construction("overflow node ID");
455+
edges[2] = 0;
456+
457+
num_vertices = static_cast<mt_kahypar_hypernode_id_t>(std::numeric_limits<HypernodeID>::max()) + 6;
458+
attempt_construction("overflow num nodes");
459+
}
460+
409461
mt_kahypar_free_hypergraph(graph);
410462
}
411463

0 commit comments

Comments
 (0)