Skip to content

Commit d0ed187

Browse files
authored
Bug Fix for #418 - Graph<T>::removeNode has potential to throw due to optional being accessed early (#430)
* optional should first check whether the node indeed exists * fixed typo in impl and also added test for removing node that was never added * incorporated review into PR * resolved use after free for map iterator * reformatted code as per PR feedback * reformatted code as per PR feedback
1 parent 28cf002 commit d0ed187

File tree

2 files changed

+61
-13
lines changed

2 files changed

+61
-13
lines changed

include/CXXGraph/Graph/Graph_impl.hpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -233,19 +233,23 @@ void Graph<T>::removeEdge(const CXXGraph::id_t edgeId) {
233233
template <typename T>
234234
void Graph<T>::removeNode(const std::string &nodeUserId) {
235235
auto nodeOpt = getNode(nodeUserId);
236-
auto isolatedNodeIt = isolatedNodesSet.find(nodeOpt.value());
237-
238-
if (nodeOpt.has_value() && isolatedNodeIt != isolatedNodesSet.end()) {
239-
// The node is isolated
240-
isolatedNodesSet.erase(isolatedNodeIt);
241-
} else if (nodeOpt.has_value()) {
242-
// The node is not isolated
243-
// Remove the edges containing the node
244-
auto edgeset = edgeSet;
245-
for (auto edgeIt : edgeset) {
246-
if (edgeIt->getNodePair().first->getUserId() == nodeUserId ||
247-
edgeIt->getNodePair().second->getUserId() == nodeUserId) {
248-
this->removeEdge(edgeIt->getId());
236+
if (nodeOpt.has_value()) {
237+
auto isolatedNodeIt = isolatedNodesSet.find(nodeOpt.value());
238+
if (isolatedNodeIt != isolatedNodesSet.end()) {
239+
// The node is isolated
240+
isolatedNodesSet.erase(isolatedNodeIt);
241+
} else {
242+
// The node is not isolated
243+
// Remove the edges containing the node
244+
auto edgeIt = edgeSet.begin();
245+
auto nextIt = edgeIt;
246+
while (edgeIt != edgeSet.end()) {
247+
nextIt = std::next(edgeIt);
248+
if ((*edgeIt)->getNodePair().first->getUserId() == nodeUserId ||
249+
(*edgeIt)->getNodePair().second->getUserId() == nodeUserId) {
250+
this->removeEdge((*edgeIt)->getId());
251+
}
252+
edgeIt = nextIt;
249253
}
250254
}
251255
}

test/GraphTest.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,6 +1340,50 @@ TEST(TestRemoveNode, Test_connectedNode) {
13401340
ASSERT_EQ(graph.getEdgeSet().size(), 1);
13411341
}
13421342

1343+
TEST(TestRemoveNode, Test_removeInvalidNode) {
1344+
/** Test to call the remove_node function on a node that was never added. In
1345+
* this case getNode will return an optional that is nullptr*/
1346+
// Create a graph with 3 nodes and 3 edges.
1347+
CXXGraph::Node<int> node1("1", 1);
1348+
CXXGraph::Node<int> node2("2", 2);
1349+
CXXGraph::Node<int> node3("3", 3);
1350+
CXXGraph::DirectedEdge<int> edge1(1, node1, node2);
1351+
CXXGraph::DirectedEdge<int> edge2(2, node2, node1);
1352+
CXXGraph::DirectedEdge<int> edge3(3, node1, node3);
1353+
CXXGraph::T_EdgeSet<int> edgeSet;
1354+
// Add the 3 edges into the graph.
1355+
edgeSet.insert(make_shared<CXXGraph::Edge<int>>(edge1));
1356+
edgeSet.insert(make_shared<CXXGraph::Edge<int>>(edge2));
1357+
edgeSet.insert(make_shared<CXXGraph::Edge<int>>(edge3));
1358+
// Initialise the graph
1359+
CXXGraph::Graph<int> graph(edgeSet);
1360+
1361+
// Check the initial number of edges and nodes. Everything should be okay so
1362+
// far
1363+
ASSERT_EQ(graph.getNodeSet().size(), 3);
1364+
ASSERT_EQ(graph.getEdgeSet().size(), 3);
1365+
1366+
// Remove a node that was never in the graph
1367+
graph.removeNode("4");
1368+
1369+
// Number of nodes and edges in the graph should remain the same
1370+
ASSERT_EQ(graph.getNodeSet().size(), 3);
1371+
ASSERT_EQ(graph.getEdgeSet().size(), 3);
1372+
1373+
// Remove an existing node, the edge associated with that node should also be
1374+
// removed. Node "3" had just outgoing edge, so there should now be 2 nodes
1375+
// and 2 edges.
1376+
graph.removeNode("3");
1377+
ASSERT_EQ(graph.getNodeSet().size(), 2);
1378+
ASSERT_EQ(graph.getEdgeSet().size(), 2);
1379+
1380+
// Remove the node that had already been removed. Should not change anything
1381+
// about the graph now, similar to when "4" was removed above
1382+
graph.removeNode("3");
1383+
ASSERT_EQ(graph.getNodeSet().size(), 2);
1384+
ASSERT_EQ(graph.getEdgeSet().size(), 2);
1385+
}
1386+
13431387
TEST(TestGetNode, Test_1) {
13441388
CXXGraph::Node<int> node1("1", 1);
13451389
CXXGraph::Node<int> node2("2", 2);

0 commit comments

Comments
 (0)