Merge pull request #1306 from Ryex/ci/address-sanitiser_on_debug_builds

This commit is contained in:
Sefa Eyeoglu 2023-07-14 10:11:34 +02:00
parent 7926170073
commit 27f6debdaf
No known key found for this signature in database
GPG Key ID: E13DFD4B47127951
5 changed files with 129 additions and 91 deletions

View File

@ -85,6 +85,38 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0")
# set CXXFLAGS for build targets
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}")
option(DEBUG_ADDRESS_SANITIZER "Enable Address Sanitizer in Debug builds" on)
# If this is a Debug build turn on address sanitiser
if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND DEBUG_ADDRESS_SANITIZER)
message(STATUS "Address Sanitizer enabled for Debug builds, Turn it off with -DDEBUG_ADDRESS_SANITIZER=off")
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
# 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()
endif()
option(ENABLE_LTO "Enable Link Time Optimization" off)
if(ENABLE_LTO)

View File

@ -42,6 +42,10 @@ class LinkTask : public Task {
m_lnk->debug(true);
}
~LinkTask() {
delete m_lnk;
}
void matcher(const IPathMatcher *filter)
{
m_lnk->matcher(filter);
@ -219,7 +223,8 @@ slots:
qDebug() << tempDir.path();
qDebug() << target_dir.path();
FS::copy c(folder, target_dir.path());
c.matcher(new RegexpMatcher("[.]?mcmeta"));
RegexpMatcher re("[.]?mcmeta");
c.matcher(&re);
c();
for(auto entry: target_dir.entryList())
@ -253,7 +258,8 @@ slots:
qDebug() << tempDir.path();
qDebug() << target_dir.path();
FS::copy c(folder, target_dir.path());
c.matcher(new RegexpMatcher("[.]?mcmeta"));
RegexpMatcher re("[.]?mcmeta");
c.matcher(&re);
c.whitelist(true);
c();
@ -460,7 +466,8 @@ slots:
qDebug() << target_dir.path();
LinkTask lnk_tsk(folder, target_dir.path());
lnk_tsk.matcher(new RegexpMatcher("[.]?mcmeta"));
RegexpMatcher re("[.]?mcmeta");
lnk_tsk.matcher(&re);
lnk_tsk.linkRecursively(true);
QObject::connect(&lnk_tsk, &Task::finished, [&]{
QVERIFY2(lnk_tsk.wasSuccessful(), "Task finished but was not successful when it should have been.");
@ -511,7 +518,8 @@ slots:
qDebug() << target_dir.path();
LinkTask lnk_tsk(folder, target_dir.path());
lnk_tsk.matcher(new RegexpMatcher("[.]?mcmeta"));
RegexpMatcher re("[.]?mcmeta");
lnk_tsk.matcher(&re);
lnk_tsk.linkRecursively(true);
lnk_tsk.whitelist(true);
QObject::connect(&lnk_tsk, &Task::finished, [&]{

View File

@ -38,6 +38,7 @@ class DummyResourceModel : public ResourceModel {
public:
DummyResourceModel() : ResourceModel(new DummyResourceAPI) {}
~DummyResourceModel() {}
[[nodiscard]] auto metaEntryBase() const -> QString override { return ""; };
@ -58,7 +59,10 @@ class DummyResourceModel : public ResourceModel {
class ResourceModelTest : public QObject {
Q_OBJECT
private slots:
void test_abstract_item_model() { [[maybe_unused]] auto tester = new QAbstractItemModelTester(new DummyResourceModel); }
void test_abstract_item_model() {
auto dummy = DummyResourceModel();
auto tester = QAbstractItemModelTester(&dummy);
}
void test_search()
{
@ -78,6 +82,8 @@ class ResourceModelTest : public QObject {
QVERIFY(processed_pack->addonId.toString() == Json::requireString(processed_response, "project_id"));
QVERIFY(processed_pack->description == Json::requireString(processed_response, "description"));
QVERIFY(processed_pack->authors.first().name == Json::requireString(processed_response, "author"));
delete model;
}
};

View File

@ -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();
}
@ -53,49 +50,42 @@ class BigConcurrentTask : public ConcurrentTask {
class BigConcurrentTaskThread : public QThread {
Q_OBJECT
BigConcurrentTask big_task;
QTimer m_deadline;
void run() override
{
QTimer deadline;
deadline.setInterval(10000);
connect(&deadline, &QTimer::timeout, this, [this]{ passed_the_deadline = true; });
deadline.start();
BigConcurrentTask big_task;
m_deadline.setInterval(10000);
// 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];
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);
}
connect(&big_task, &Task::finished, this, &QThread::quit);
connect(&m_deadline, &QTimer::timeout, this, [&] { passed_the_deadline = true; quit(); });
m_deadline.start();
big_task.run();
while (!big_task.isFinished() && !passed_the_deadline)
QCoreApplication::processEvents();
emit finished();
exec();
}
public:
bool passed_the_deadline = false;
signals:
void finished();
};
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);
@ -103,9 +93,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);
@ -115,7 +106,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;
@ -126,17 +118,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>();
@ -147,7 +140,7 @@ class TaskTest : public QObject {
t.addTask(t2);
t.addTask(t3);
QObject::connect(&t, &Task::finished, [&]{
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());
@ -155,13 +148,12 @@ class TaskTest : public QObject {
});
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>();
@ -184,7 +176,7 @@ class TaskTest : public QObject {
t.addTask(t8);
t.addTask(t9);
QObject::connect(&t, &Task::finished, [&]{
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());
@ -198,12 +190,11 @@ class TaskTest : public QObject {
});
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>();
@ -214,7 +205,7 @@ class TaskTest : public QObject {
t.addTask(t2);
t.addTask(t3);
QObject::connect(&t, &Task::finished, [&]{
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());
@ -222,12 +213,11 @@ class TaskTest : public QObject {
});
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>();
@ -238,7 +228,7 @@ class TaskTest : public QObject {
t.addTask(t2);
t.addTask(t3);
QObject::connect(&t, &Task::finished, [&]{
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());
@ -246,25 +236,22 @@ class TaskTest : public QObject {
});
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()
{
QEventLoop loop;
auto thread = new BigConcurrentTaskThread;
BigConcurrentTaskThread thread;
connect(thread, &BigConcurrentTaskThread::finished, &loop, &QEventLoop::quit);
connect(&thread, &BigConcurrentTaskThread::finished, &loop, &QEventLoop::quit);
thread->start();
thread.start();
loop.exec();
QVERIFY(!thread->passed_the_deadline);
thread->deleteLater();
QVERIFY(!thread.passed_the_deadline);
}
};

View File

@ -20,6 +20,8 @@
class VersionTest : public QObject {
Q_OBJECT
QStringList m_flex_test_names = {};
void addDataColumns()
{
QTest::addColumn<QString>("first");
@ -101,8 +103,9 @@ class VersionTest : public QObject {
QString first{split_line.first().simplified()};
QString second{split_line.last().simplified()};
auto new_test_name = test_name_template.arg(QString::number(test_number), "lessThan").toLatin1().data();
QTest::newRow(new_test_name) << first << second << true << false;
auto new_test_name = test_name_template.arg(QString::number(test_number), "lessThan");
m_flex_test_names.append(new_test_name);
QTest::newRow(m_flex_test_names.last().toLatin1().data()) << first << second << true << false;
continue;
}
@ -112,8 +115,9 @@ class VersionTest : public QObject {
QString first{split_line.first().simplified()};
QString second{split_line.last().simplified()};
auto new_test_name = test_name_template.arg(QString::number(test_number), "equals").toLatin1().data();
QTest::newRow(new_test_name) << first << second << false << true;
auto new_test_name = test_name_template.arg(QString::number(test_number), "equals");
m_flex_test_names.append(new_test_name);
QTest::newRow(m_flex_test_names.last().toLatin1().data()) << first << second << false << true;
continue;
}
@ -123,8 +127,9 @@ class VersionTest : public QObject {
QString first{split_line.first().simplified()};
QString second{split_line.last().simplified()};
auto new_test_name = test_name_template.arg(QString::number(test_number), "greaterThan").toLatin1().data();
QTest::newRow(new_test_name) << first << second << false << false;
auto new_test_name = test_name_template.arg(QString::number(test_number), "greaterThan");
m_flex_test_names.append(new_test_name);
QTest::newRow(m_flex_test_names.last().toLatin1().data()) << first << second << false << false;
continue;
}