From 4dbcedd03f6d90a9557cd401c2236f9cda60cf9f Mon Sep 17 00:00:00 2001
From: Rachel Powers <508861+Ryex@users.noreply.github.com>
Date: Wed, 5 Jul 2023 11:51:37 -0700
Subject: fix: Task test memory leaks again

Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
---
 CMakeLists.txt      |   5 ++
 tests/Task_test.cpp | 138 +++++++++++++++++++++++++---------------------------
 2 files changed, 72 insertions(+), 71 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4f8befcc..afa67546 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -95,18 +95,23 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND DEBUG_ADDRESS_SANITIZER)
             # using clang with clang-cl front end 
             message(STATUS "Address Sanitizer available on Clang MSVC frontend")
             set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /O1 /Oy-")
+            set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /O1 /Oy-")
         else()
             # AppleClang and Clang
             message(STATUS "Address Sanitizer available on Clang")
             set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer")
+            set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer")
         endif()
     elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
         # GCC
         message(STATUS "Address Sanitizer available on GCC")
         set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer")
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -O1 -fno-omit-frame-pointer")
+        link_libraries("asan")
     elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
         message(STATUS "Address Sanitizer available on MSVC")
         set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /O1 /Oy-")
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /O1 /Oy-")
     else()
         message(STATUS "Address Sanitizer not available on compiler ${CMAKE_CXX_COMPILER_ID}")
     endif()
diff --git a/tests/Task_test.cpp b/tests/Task_test.cpp
index a57102d6..b6bd7edf 100644
--- a/tests/Task_test.cpp
+++ b/tests/Task_test.cpp
@@ -1,6 +1,6 @@
 #include <QTest>
-#include <QTimer>
 #include <QThread>
+#include <QTimer>
 
 #include <tasks/ConcurrentTask.h>
 #include <tasks/MultipleOptionsTask.h>
@@ -19,10 +19,7 @@ class BasicTask : public Task {
     BasicTask(bool show_debug_log = true) : Task(nullptr, show_debug_log) {}
 
    private:
-    void executeTask() override
-    {
-        emitSucceeded();
-    };
+    void executeTask() override { emitSucceeded(); };
 };
 
 /* Does nothing. Only used for testing. */
@@ -34,7 +31,7 @@ class BasicTask_MultiStep : public Task {
    private:
     auto isMultiStep() const -> bool override { return true; }
 
-    void executeTask() override {};   
+    void executeTask() override{};
 };
 
 class BigConcurrentTask : public ConcurrentTask {
@@ -44,7 +41,7 @@ class BigConcurrentTask : public ConcurrentTask {
     {
         // This is here only to help fill the stack a bit more quickly (if there's an issue, of course :^))
         // Each tasks thus adds 1024 * 4 bytes to the stack, at the very least.
-        [[maybe_unused]] volatile std::array<uint32_t, 1024> some_data_on_the_stack {};
+        [[maybe_unused]] volatile std::array<uint32_t, 1024> some_data_on_the_stack{};
 
         ConcurrentTask::startNext();
     }
@@ -59,28 +56,28 @@ class BigConcurrentTaskThread : public QThread {
     {
         QTimer deadline;
         deadline.setInterval(10000);
-        connect(&deadline, &QTimer::timeout, this, [this]{ passed_the_deadline = true; });
+        connect(&deadline, &QTimer::timeout, this, [this] { passed_the_deadline = true; });
         deadline.start();
 
         // NOTE: Arbitrary value that manages to trigger a problem when there is one.
         //       Considering each tasks, in a problematic state, adds 1024 * 4 bytes to the stack,
         //       this number is enough to fill up 16 MiB of stack, more than enough to cause a problem.
         static const unsigned s_num_tasks = 1 << 12;
-        auto sub_tasks = new BasicTask::Ptr[s_num_tasks];
+        {
+            auto sub_tasks = std::array<BasicTask::Ptr, s_num_tasks>();
 
-        for (unsigned i = 0; i < s_num_tasks; i++) {
-            auto sub_task = makeShared<BasicTask>(false);
-            sub_tasks[i] = sub_task;
-            big_task.addTask(sub_task);
-        }
+            for (unsigned i = 0; i < s_num_tasks; i++) {
+                auto sub_task = makeShared<BasicTask>(false);
+                sub_tasks[i] = sub_task;
+                big_task.addTask(sub_task);
+            }
 
-        big_task.run();
-
-        while (!big_task.isFinished() && !passed_the_deadline)
-            QCoreApplication::processEvents();
+            big_task.run();
 
+            while (!big_task.isFinished() && !passed_the_deadline)
+                QCoreApplication::processEvents();
+        } // drop before emit
         emit finished();
-        delete[] sub_tasks;
     }
 
    public:
@@ -94,9 +91,10 @@ class TaskTest : public QObject {
     Q_OBJECT
 
    private slots:
-    void test_SetStatus_NoMultiStep(){
+    void test_SetStatus_NoMultiStep()
+    {
         BasicTask t;
-        QString status {"test status"};
+        QString status{ "test status" };
 
         t.setStatus(status);
 
@@ -104,9 +102,10 @@ class TaskTest : public QObject {
         QCOMPARE(t.getStepProgress().isEmpty(), TaskStepProgressList{}.isEmpty());
     }
 
-    void test_SetStatus_MultiStep(){
+    void test_SetStatus_MultiStep()
+    {
         BasicTask_MultiStep t;
-        QString status {"test status"};
+        QString status{ "test status" };
 
         t.setStatus(status);
 
@@ -116,7 +115,8 @@ class TaskTest : public QObject {
         QCOMPARE(t.getStepProgress().isEmpty(), TaskStepProgressList{}.isEmpty());
     }
 
-    void test_SetProgress(){
+    void test_SetProgress()
+    {
         BasicTask t;
         int current = 42;
         int total = 207;
@@ -127,17 +127,18 @@ class TaskTest : public QObject {
         QCOMPARE(t.getTotalProgress(), total);
     }
 
-    void test_basicRun(){
+    void test_basicRun()
+    {
         BasicTask t;
-        QObject::connect(&t, &Task::finished, [&]{ QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been."); });
+        QObject::connect(&t, &Task::finished,
+                         [&] { QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been."); });
         t.start();
 
-        QVERIFY2(QTest::qWaitFor([&]() {
-            return t.isFinished();
-        }, 1000), "Task didn't finish as it should.");
+        QVERIFY2(QTest::qWaitFor([&]() { return t.isFinished(); }, 1000), "Task didn't finish as it should.");
     }
 
-    void test_basicConcurrentRun(){
+    void test_basicConcurrentRun()
+    {
         auto t1 = makeShared<BasicTask>();
         auto t2 = makeShared<BasicTask>();
         auto t3 = makeShared<BasicTask>();
@@ -148,21 +149,20 @@ class TaskTest : public QObject {
         t.addTask(t2);
         t.addTask(t3);
 
-        QObject::connect(&t, &Task::finished, [&]{
-                QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
-                QVERIFY(t1->wasSuccessful());
-                QVERIFY(t2->wasSuccessful());
-                QVERIFY(t3->wasSuccessful());
+        QObject::connect(&t, &Task::finished, [&t, &t1, &t2, &t3] {
+            QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
+            QVERIFY(t1->wasSuccessful());
+            QVERIFY(t2->wasSuccessful());
+            QVERIFY(t3->wasSuccessful());
         });
 
         t.start();
-        QVERIFY2(QTest::qWaitFor([&]() {
-            return t.isFinished();
-        }, 1000), "Task didn't finish as it should.");
+        QVERIFY2(QTest::qWaitFor([&]() { return t.isFinished(); }, 1000), "Task didn't finish as it should.");
     }
 
     // Tests if starting new tasks after the 6 initial ones is working
-    void test_moreConcurrentRun(){
+    void test_moreConcurrentRun()
+    {
         auto t1 = makeShared<BasicTask>();
         auto t2 = makeShared<BasicTask>();
         auto t3 = makeShared<BasicTask>();
@@ -185,26 +185,25 @@ class TaskTest : public QObject {
         t.addTask(t8);
         t.addTask(t9);
 
-        QObject::connect(&t, &Task::finished, [&]{
-                QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
-                QVERIFY(t1->wasSuccessful());
-                QVERIFY(t2->wasSuccessful());
-                QVERIFY(t3->wasSuccessful());
-                QVERIFY(t4->wasSuccessful());
-                QVERIFY(t5->wasSuccessful());
-                QVERIFY(t6->wasSuccessful());
-                QVERIFY(t7->wasSuccessful());
-                QVERIFY(t8->wasSuccessful());
-                QVERIFY(t9->wasSuccessful());
+        QObject::connect(&t, &Task::finished, [&t, &t1, &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9] {
+            QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
+            QVERIFY(t1->wasSuccessful());
+            QVERIFY(t2->wasSuccessful());
+            QVERIFY(t3->wasSuccessful());
+            QVERIFY(t4->wasSuccessful());
+            QVERIFY(t5->wasSuccessful());
+            QVERIFY(t6->wasSuccessful());
+            QVERIFY(t7->wasSuccessful());
+            QVERIFY(t8->wasSuccessful());
+            QVERIFY(t9->wasSuccessful());
         });
 
         t.start();
-        QVERIFY2(QTest::qWaitFor([&]() {
-            return t.isFinished();
-        }, 1000), "Task didn't finish as it should.");
+        QVERIFY2(QTest::qWaitFor([&]() { return t.isFinished(); }, 1000), "Task didn't finish as it should.");
     }
 
-    void test_basicSequentialRun(){
+    void test_basicSequentialRun()
+    {
         auto t1 = makeShared<BasicTask>();
         auto t2 = makeShared<BasicTask>();
         auto t3 = makeShared<BasicTask>();
@@ -215,20 +214,19 @@ class TaskTest : public QObject {
         t.addTask(t2);
         t.addTask(t3);
 
-        QObject::connect(&t, &Task::finished, [&]{
-                QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
-                QVERIFY(t1->wasSuccessful());
-                QVERIFY(t2->wasSuccessful());
-                QVERIFY(t3->wasSuccessful());
+        QObject::connect(&t, &Task::finished, [&t, &t1, &t2, &t3] {
+            QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
+            QVERIFY(t1->wasSuccessful());
+            QVERIFY(t2->wasSuccessful());
+            QVERIFY(t3->wasSuccessful());
         });
 
         t.start();
-        QVERIFY2(QTest::qWaitFor([&]() {
-            return t.isFinished();
-        }, 1000), "Task didn't finish as it should.");
+        QVERIFY2(QTest::qWaitFor([&]() { return t.isFinished(); }, 1000), "Task didn't finish as it should.");
     }
 
-    void test_basicMultipleOptionsRun(){
+    void test_basicMultipleOptionsRun()
+    {
         auto t1 = makeShared<BasicTask>();
         auto t2 = makeShared<BasicTask>();
         auto t3 = makeShared<BasicTask>();
@@ -239,17 +237,15 @@ class TaskTest : public QObject {
         t.addTask(t2);
         t.addTask(t3);
 
-        QObject::connect(&t, &Task::finished, [&]{
-                QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
-                QVERIFY(t1->wasSuccessful());
-                QVERIFY(!t2->wasSuccessful());
-                QVERIFY(!t3->wasSuccessful());
+        QObject::connect(&t, &Task::finished, [&t, &t1, &t2, &t3] {
+            QVERIFY2(t.wasSuccessful(), "Task finished but was not successful when it should have been.");
+            QVERIFY(t1->wasSuccessful());
+            QVERIFY(!t2->wasSuccessful());
+            QVERIFY(!t3->wasSuccessful());
         });
 
         t.start();
-        QVERIFY2(QTest::qWaitFor([&]() {
-            return t.isFinished();
-        }, 1000), "Task didn't finish as it should.");
+        QVERIFY2(QTest::qWaitFor([&]() { return t.isFinished(); }, 1000), "Task didn't finish as it should.");
     }
 
     void test_stackOverflowInConcurrentTask()
-- 
cgit