Skip to content

Commit e9f9ed2

Browse files
authored
Enhance memory leak detection (#245)
* Change Debug -> COVERAGE flag and add fsanitize=address * Add virtual destructor to prevent memory leaks * Make m_agents private for security reasons * Refactor one line * Fix compile-time warnings * Update version * Fix apple-clang warning
1 parent 87dbbfb commit e9f9ed2

File tree

10 files changed

+52
-55
lines changed

10 files changed

+52
-55
lines changed

.github/workflows/cmake_test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
branches: [ "main" ]
88

99
env:
10-
BUILD_TYPE: Debug
10+
BUILD_TYPE: COVERAGE
1111

1212
jobs:
1313
build:

.github/workflows/cmake_test_macos.yml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ on:
66
pull_request:
77
branches: [ "main" ]
88

9-
env:
10-
BUILD_TYPE: Debug
11-
129
jobs:
1310
build:
1411
runs-on: macos-latest
@@ -18,12 +15,12 @@ jobs:
1815

1916
- name: Configure CMake
2017
working-directory: ${{github.workspace}}/test
21-
run: cmake -B ${{github.workspace}}/test/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
18+
run: cmake -B ${{github.workspace}}/test/build
2219

2320
- name: Build
2421
working-directory: ${{github.workspace}}/test
2522
# Build your program with the given configuration
26-
run: cmake --build ${{github.workspace}}/test/build --config ${{env.BUILD_TYPE}}
23+
run: cmake --build ${{github.workspace}}/test/build
2724

2825
- name: Run tests
2926
working-directory: ${{github.workspace}}/test

src/dsm/dsm.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
static constexpr uint8_t DSM_VERSION_MAJOR = 2;
88
static constexpr uint8_t DSM_VERSION_MINOR = 3;
9-
static constexpr uint8_t DSM_VERSION_PATCH = 0;
9+
static constexpr uint8_t DSM_VERSION_PATCH = 1;
1010

1111
static auto const DSM_VERSION =
1212
std::format("{}.{}.{}", DSM_VERSION_MAJOR, DSM_VERSION_MINOR, DSM_VERSION_PATCH);

src/dsm/headers/Dynamics.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,11 @@ namespace dsm {
6464
/// @tparam Size, The type of the graph's capacity. It must be an unsigned integral type.
6565
template <typename agent_t>
6666
class Dynamics {
67+
private:
68+
std::map<Id, std::unique_ptr<agent_t>> m_agents;
69+
6770
protected:
6871
std::unordered_map<Id, std::unique_ptr<Itinerary>> m_itineraries;
69-
std::map<Id, std::unique_ptr<agent_t>> m_agents;
7072
Graph m_graph;
7173
Time m_time, m_previousSpireTime;
7274
std::mt19937_64 m_generator;

src/dsm/headers/FirstOrderDynamics.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace dsm {
2727
}
2828

2929
void FirstOrderDynamics::setAgentSpeed(Size agentId) {
30-
const auto& agent{this->m_agents[agentId]};
30+
const auto& agent{this->agents().at(agentId)};
3131
const auto& street{this->m_graph.streetSet()[agent->streetId().value()]};
3232
double speed{street->maxSpeed() * (1. - m_alpha * street->density(true))};
3333
if (m_speedFluctuationSTD > 0.) {
@@ -59,12 +59,12 @@ namespace dsm {
5959
meanSpeed = street->maxSpeed() * n * (1. - 0.5 * alpha * (n - 1.));
6060
} else {
6161
for (const auto& agentId : street->waitingAgents()) {
62-
meanSpeed += this->m_agents.at(agentId)->speed();
62+
meanSpeed += this->agents().at(agentId)->speed();
6363
++n;
6464
}
6565
for (auto const& queue : street->exitQueues()) {
6666
for (const auto& agentId : queue) {
67-
meanSpeed += this->m_agents.at(agentId)->speed();
67+
meanSpeed += this->agents().at(agentId)->speed();
6868
++n;
6969
}
7070
}
@@ -73,7 +73,7 @@ namespace dsm {
7373
if (node->isIntersection()) {
7474
auto& intersection = dynamic_cast<Intersection&>(*node);
7575
for (const auto& [angle, agentId] : intersection.agents()) {
76-
const auto& agent{this->m_agents.at(agentId)};
76+
const auto& agent{this->agents().at(agentId)};
7777
if (agent->streetId().has_value() && agent->streetId().value() == streetId) {
7878
meanSpeed += agent->speed();
7979
++n;
@@ -82,7 +82,7 @@ namespace dsm {
8282
} else if (node->isRoundabout()) {
8383
auto& roundabout = dynamic_cast<Roundabout&>(*node);
8484
for (const auto& agentId : roundabout.agents()) {
85-
const auto& agent{this->m_agents.at(agentId)};
85+
const auto& agent{this->agents().at(agentId)};
8686
if (agent->streetId().has_value() && agent->streetId().value() == streetId) {
8787
meanSpeed += agent->speed();
8888
++n;
@@ -93,7 +93,7 @@ namespace dsm {
9393
}
9494

9595
Measurement<double> FirstOrderDynamics::streetMeanSpeed() const {
96-
if (this->m_agents.size() == 0) {
96+
if (this->agents().empty()) {
9797
return Measurement(0., 0.);
9898
}
9999
std::vector<double> speeds;
@@ -105,7 +105,7 @@ namespace dsm {
105105
}
106106
Measurement<double> FirstOrderDynamics::streetMeanSpeed(double threshold,
107107
bool above) const {
108-
if (this->m_agents.size() == 0) {
108+
if (this->agents().empty()) {
109109
return Measurement(0., 0.);
110110
}
111111
std::vector<double> speeds;

src/dsm/headers/Graph.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,8 @@ namespace dsm {
5252
throw std::invalid_argument(buildLog("Street with same id already exists."));
5353
}
5454
if (street->isSpire()) {
55-
m_streets.emplace(
56-
newStreetId,
57-
std::make_unique<SpireStreet>(SpireStreet{newStreetId, *street}));
55+
m_streets.emplace(newStreetId,
56+
std::make_unique<SpireStreet>(newStreetId, *street));
5857
} else {
5958
m_streets.emplace(newStreetId,
6059
std::make_unique<Street>(Street{newStreetId, *street}));

src/dsm/headers/RoadDynamics.hpp

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ namespace dsm {
196196
Id RoadDynamics<delay_t>::m_nextStreetId(Id agentId,
197197
Id nodeId,
198198
std::optional<Id> streetId) {
199-
auto const& pAgent{this->m_agents[agentId]};
199+
auto const& pAgent{this->agents().at(agentId)};
200200
auto possibleMoves = this->m_graph.adjMatrix().getRow(nodeId, true);
201201
if (!pAgent->isRandom()) {
202202
std::uniform_real_distribution<double> uniformDist{0., 1.};
@@ -253,7 +253,7 @@ namespace dsm {
253253
continue;
254254
}
255255
const auto agentId{pStreet->queue(queueIndex).front()};
256-
auto const& pAgent{this->m_agents[agentId]};
256+
auto const& pAgent{this->agents().at(agentId)};
257257
if (pAgent->delay() > 0) {
258258
continue;
259259
}
@@ -331,10 +331,10 @@ namespace dsm {
331331
continue;
332332
}
333333
intersection.removeAgent(agentId);
334-
this->m_agents[agentId]->setStreetId(nextStreet->id());
334+
this->agents().at(agentId)->setStreetId(nextStreet->id());
335335
this->setAgentSpeed(agentId);
336-
this->m_agents[agentId]->incrementDelay(
337-
std::ceil(nextStreet->length() / this->m_agents[agentId]->speed()));
336+
this->agents().at(agentId)->incrementDelay(
337+
std::ceil(nextStreet->length() / this->agents().at(agentId)->speed()));
338338
nextStreet->addAgent(agentId);
339339
m_agentNextStreetId.erase(agentId);
340340
return true;
@@ -348,8 +348,8 @@ namespace dsm {
348348
auto const agentId{roundabout.agents().front()};
349349
auto const& nextStreet{this->m_graph.streetSet()[m_agentNextStreetId[agentId]]};
350350
if (!(nextStreet->isFull())) {
351-
if (this->m_agents[agentId]->streetId().has_value()) {
352-
const auto streetId = this->m_agents[agentId]->streetId().value();
351+
if (this->agents().at(agentId)->streetId().has_value()) {
352+
const auto streetId = this->agents().at(agentId)->streetId().value();
353353
auto delta = nextStreet->angle() - this->m_graph.streetSet()[streetId]->angle();
354354
if (delta > std::numbers::pi) {
355355
delta -= 2 * std::numbers::pi;
@@ -359,10 +359,10 @@ namespace dsm {
359359
m_increaseTurnCounts(streetId, delta);
360360
}
361361
roundabout.dequeue();
362-
this->m_agents[agentId]->setStreetId(nextStreet->id());
362+
this->agents().at(agentId)->setStreetId(nextStreet->id());
363363
this->setAgentSpeed(agentId);
364-
this->m_agents[agentId]->incrementDelay(
365-
std::ceil(nextStreet->length() / this->m_agents[agentId]->speed()));
364+
this->agents().at(agentId)->incrementDelay(
365+
std::ceil(nextStreet->length() / this->agents().at(agentId)->speed()));
366366
nextStreet->addAgent(agentId);
367367
m_agentNextStreetId.erase(agentId);
368368
} else {
@@ -377,7 +377,7 @@ namespace dsm {
377377
void RoadDynamics<delay_t>::m_evolveAgents() {
378378
std::uniform_int_distribution<Id> nodeDist{
379379
0, static_cast<Id>(this->m_graph.nNodes() - 1)};
380-
for (const auto& [agentId, agent] : this->m_agents) {
380+
for (const auto& [agentId, agent] : this->agents()) {
381381
if (agent->delay() > 0) {
382382
const auto& street{this->m_graph.streetSet()[agent->streetId().value()]};
383383
if (agent->delay() > 1) {
@@ -517,8 +517,8 @@ namespace dsm {
517517
itineraryId = itineraryIt->first;
518518
}
519519
Id agentId{0};
520-
if (!this->m_agents.empty()) {
521-
agentId = this->m_agents.rbegin()->first + 1;
520+
if (!this->agents().empty()) {
521+
agentId = this->agents().rbegin()->first + 1;
522522
}
523523
Id streetId{0};
524524
do {
@@ -527,13 +527,13 @@ namespace dsm {
527527
std::advance(streetIt, step);
528528
streetId = streetIt->first;
529529
} while (this->m_graph.streetSet()[streetId]->isFull() &&
530-
this->m_agents.size() < this->m_graph.maxCapacity());
530+
this->nAgents() < this->m_graph.maxCapacity());
531531
const auto& street{this->m_graph.streetSet()[streetId]};
532532
this->addAgent(agentId, itineraryId, street->nodePair().first);
533-
this->m_agents[agentId]->setStreetId(streetId);
533+
this->agents().at(agentId)->setStreetId(streetId);
534534
this->setAgentSpeed(agentId);
535-
this->m_agents[agentId]->incrementDelay(
536-
std::ceil(street->length() / this->m_agents[agentId]->speed()));
535+
this->agents().at(agentId)->incrementDelay(
536+
std::ceil(street->length() / this->agents().at(agentId)->speed()));
537537
street->addAgent(agentId);
538538
++agentId;
539539
}
@@ -579,8 +579,8 @@ namespace dsm {
579579
std::uniform_real_distribution<double> srcUniformDist{0., srcSum};
580580
std::uniform_real_distribution<double> dstUniformDist{0., dstSum};
581581
Id agentId{0};
582-
if (!this->m_agents.empty()) {
583-
agentId = this->m_agents.rbegin()->first + 1;
582+
if (!this->agents().empty()) {
583+
agentId = this->agents().rbegin()->first + 1;
584584
}
585585
while (nAgents > 0) {
586586
Id srcId{0}, dstId{0};

src/dsm/headers/Street.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ namespace dsm {
6868
std::string name = std::string(),
6969
std::optional<int> capacity = std::nullopt,
7070
int transportCapacity = 1);
71+
virtual ~Street() = default;
7172

7273
/// @brief Set the street's queue
7374
/// @param queue The street's queue

test/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
88
set(CMAKE_CXX_EXTENSIONS OFF)
99

1010
# Add code coverage options
11-
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
11+
if(CMAKE_BUILD_TYPE STREQUAL "COVERAGE")
1212
message(STATUS "Enable code coverage")
1313
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -g --coverage -fprofile-update=atomic")
1414
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
15+
else()
16+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -g -fsanitize=address")
1517
endif()
1618

1719
# Set the folder for the executable

test/Test_dynamics.cpp

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,6 @@ TEST_CASE("Dynamics") {
645645
graph2.buildAdj();
646646
graph2.adjustNodeCapacities();
647647
auto const& nodes = graph2.nodeSet();
648-
auto& tl = dynamic_cast<TrafficLight&>(*nodes.at(1));
649648
nodes.at(0)->setCoords({0., -1.});
650649
nodes.at(2)->setCoords({0., 1.});
651650
nodes.at(3)->setCoords({-1., 0.});
@@ -715,7 +714,6 @@ TEST_CASE("Dynamics") {
715714
graph2.buildAdj();
716715
graph2.adjustNodeCapacities();
717716
auto const& nodes = graph2.nodeSet();
718-
auto& tl = dynamic_cast<TrafficLight&>(*nodes.at(1));
719717
nodes.at(0)->setCoords({0., -1.});
720718
nodes.at(2)->setCoords({0., 1.});
721719
nodes.at(3)->setCoords({-1., 0.});
@@ -781,7 +779,6 @@ TEST_CASE("Dynamics") {
781779
Dynamics dynamics{graph2, 69};
782780
std::vector<dsm::Id> destinationNodes{0, 2, 3, 4};
783781
dynamics.setDestinationNodes(destinationNodes);
784-
auto const& cycles{tl.cycles()};
785782
WHEN("We evolve the dynamics and optimize traffic lights") {
786783
dynamics.addAgents(7, 0, 2);
787784
dynamics.addAgents(7, 2, 0);
@@ -923,7 +920,6 @@ TEST_CASE("Dynamics") {
923920
CHECK_EQ(dynamics.streetMeanSpeed(0.2, true).std, 0.);
924921
CHECK_EQ(dynamics.streetMeanSpeed(0.2, false).mean, 15.);
925922
CHECK_EQ(dynamics.streetMeanSpeed(0.2, false).std, 0.);
926-
(10, 0, 0);
927923
dynamics.evolve(false);
928924
meanSpeed = 0.;
929925
for (const auto& [agentId, agent] : dynamics.agents()) {
@@ -940,19 +936,19 @@ TEST_CASE("Dynamics") {
940936
SUBCASE("Intersection priorities") {
941937
GIVEN("A dynamics object with five nodes and eight streets") {
942938
Graph graph2;
943-
auto& nodeO = graph2.addNode<Intersection>(0, std::make_pair(0, 0));
944-
auto& nodeA = graph2.addNode<Intersection>(1, std::make_pair(-1, 1));
945-
auto& nodeB = graph2.addNode<Intersection>(2, std::make_pair(1, 1));
946-
auto& nodeC = graph2.addNode<Intersection>(3, std::make_pair(1, -1));
947-
auto& nodeD = graph2.addNode<Intersection>(4, std::make_pair(-1, -1));
948-
auto& sOA = graph2.addEdge<Street>(0, std::make_pair(0, 1), 10., 10.);
949-
auto& sOB = graph2.addEdge<Street>(1, std::make_pair(0, 2), 10., 10.);
950-
auto& sOC = graph2.addEdge<Street>(2, std::make_pair(0, 3), 10., 10.);
951-
auto& sOD = graph2.addEdge<Street>(3, std::make_pair(0, 4), 10., 10.);
952-
auto& sAO = graph2.addEdge<Street>(4, std::make_pair(1, 0), 10., 10.);
953-
auto& sBO = graph2.addEdge<Street>(5, std::make_pair(2, 0), 10., 10.);
954-
auto& sCO = graph2.addEdge<Street>(6, std::make_pair(3, 0), 10., 10.);
955-
auto& sDO = graph2.addEdge<Street>(7, std::make_pair(4, 0), 10., 10.);
939+
graph2.addNode<Intersection>(0, std::make_pair(0, 0));
940+
graph2.addNode<Intersection>(1, std::make_pair(-1, 1));
941+
graph2.addNode<Intersection>(2, std::make_pair(1, 1));
942+
graph2.addNode<Intersection>(3, std::make_pair(1, -1));
943+
graph2.addNode<Intersection>(4, std::make_pair(-1, -1));
944+
graph2.addEdge<Street>(0, std::make_pair(0, 1), 10., 10.);
945+
graph2.addEdge<Street>(1, std::make_pair(0, 2), 10., 10.);
946+
graph2.addEdge<Street>(2, std::make_pair(0, 3), 10., 10.);
947+
graph2.addEdge<Street>(3, std::make_pair(0, 4), 10., 10.);
948+
graph2.addEdge<Street>(4, std::make_pair(1, 0), 10., 10.);
949+
graph2.addEdge<Street>(5, std::make_pair(2, 0), 10., 10.);
950+
graph2.addEdge<Street>(6, std::make_pair(3, 0), 10., 10.);
951+
graph2.addEdge<Street>(7, std::make_pair(4, 0), 10., 10.);
956952
graph2.buildAdj();
957953
Dynamics dynamics{graph2, 69};
958954
dynamics.graph().nodeSet().at(0)->setCapacity(3);

0 commit comments

Comments
 (0)