Commit 3ddbc351 authored by Stefan Brüns's avatar Stefan Brüns
Browse files

Avoid double free/use-after-free of static unique_ptr<>

The processtest autotest crashes as the static ProcessLocal is apparently
destructed twice from the global destructor list on program exit. The
issue can be triggered even with a trivial program:

```
int main(int argc, char* argv[])
{
    QApplication app(argc, argv);
    KSysGuardProcessList processList;
}
```
parent 9c17f75e
find_package(Qt5 REQUIRED CONFIG COMPONENTS Test) find_package(Qt5 REQUIRED CONFIG COMPONENTS Test)
include_directories(${libksysguard_SOURCE_DIR}) include_directories(${libksysguard_SOURCE_DIR})
if(Qt5WebEngineWidgets_FOUND)
# Process unit test # Process unit test
ecm_qt_declare_logging_category(processtest_debug_SRCS HEADER processcore_debug.h IDENTIFIER LIBKSYSGUARD_PROCESSCORE CATEGORY_NAME org.kde.libksysguard.processcore) ecm_qt_declare_logging_category(processtest_debug_SRCS HEADER processcore_debug.h IDENTIFIER LIBKSYSGUARD_PROCESSCORE CATEGORY_NAME org.kde.libksysguard.processcore)
ecm_add_test(processtest.cpp ${processtest_debug_SRCS} TEST_NAME processtest ecm_add_test(processtest.cpp ${processtest_debug_SRCS} TEST_NAME processtest
LINK_LIBRARIES KSysGuard::ProcessUi Qt5::Test) LINK_LIBRARIES KSysGuard::ProcessUi Qt5::Test)
endif()
if (KF5Plasma_FOUND) if (KF5Plasma_FOUND)
set(SIGNALPLOTTER_DEBUG_SRCS) set(SIGNALPLOTTER_DEBUG_SRCS)
......
...@@ -47,21 +47,16 @@ public: ...@@ -47,21 +47,16 @@ public:
QVector<int> listToVector(const QVariantList &list); QVector<int> listToVector(const QVariantList &list);
QWidget *widget; QWidget *widget;
// Note: This instance is only to have access to the platform-specific code
// for sending signals, setting priority etc. Therefore, it should never be
// used to access information about processes.
static std::unique_ptr<ProcessesLocal> localProcesses;
}; };
std::unique_ptr<ProcessesLocal> ProcessController::Private::localProcesses; // Note: This instance is only to have access to the platform-specific code
// for sending signals, setting priority etc. Therefore, it should never be
// used to access information about processes.
Q_GLOBAL_STATIC(ProcessesLocal, s_localProcesses);
ProcessController::ProcessController(QObject* parent) ProcessController::ProcessController(QObject* parent)
: QObject(parent), d(new Private) : QObject(parent), d(new Private)
{ {
if (!d->localProcesses) {
d->localProcesses = std::make_unique<ProcessesLocal>();
}
} }
KSysGuard::ProcessController::~ProcessController() KSysGuard::ProcessController::~ProcessController()
...@@ -83,7 +78,7 @@ ProcessController::Result ProcessController::sendSignal(const QVector<int>& pids ...@@ -83,7 +78,7 @@ ProcessController::Result ProcessController::sendSignal(const QVector<int>& pids
{ {
qCDebug(LIBKSYSGUARD_PROCESSCORE) << "Sending signal" << signal << "to" << pids; qCDebug(LIBKSYSGUARD_PROCESSCORE) << "Sending signal" << signal << "to" << pids;
auto result = d->applyToPids(pids, [this, signal](int pid) { return d->localProcesses->sendSignal(pid, signal); }); auto result = d->applyToPids(pids, [this, signal](int pid) { return s_localProcesses->sendSignal(pid, signal); });
if (result.unchanged.isEmpty()) { if (result.unchanged.isEmpty()) {
return result.resultCode; return result.resultCode;
} }
...@@ -107,7 +102,7 @@ KSysGuard::ProcessController::Result KSysGuard::ProcessController::sendSignal(co ...@@ -107,7 +102,7 @@ KSysGuard::ProcessController::Result KSysGuard::ProcessController::sendSignal(co
ProcessController::Result ProcessController::setPriority(const QVector<int>& pids, int priority) ProcessController::Result ProcessController::setPriority(const QVector<int>& pids, int priority)
{ {
auto result = d->applyToPids(pids, [this, priority](int pid) { return d->localProcesses->setNiceness(pid, priority); }); auto result = d->applyToPids(pids, [this, priority](int pid) { return s_localProcesses->setNiceness(pid, priority); });
if (result.unchanged.isEmpty()) { if (result.unchanged.isEmpty()) {
return result.resultCode; return result.resultCode;
} }
...@@ -136,7 +131,7 @@ ProcessController::Result ProcessController::setCPUScheduler(const QVector<int>& ...@@ -136,7 +131,7 @@ ProcessController::Result ProcessController::setCPUScheduler(const QVector<int>&
} }
auto result = d->applyToPids(pids, [this, scheduler, priority](int pid) { auto result = d->applyToPids(pids, [this, scheduler, priority](int pid) {
return d->localProcesses->setScheduler(pid, scheduler, priority); return s_localProcesses->setScheduler(pid, scheduler, priority);
}); });
if (result.unchanged.isEmpty()) { if (result.unchanged.isEmpty()) {
return result.resultCode; return result.resultCode;
...@@ -161,7 +156,7 @@ KSysGuard::ProcessController::Result KSysGuard::ProcessController::setCPUSchedul ...@@ -161,7 +156,7 @@ KSysGuard::ProcessController::Result KSysGuard::ProcessController::setCPUSchedul
ProcessController::Result ProcessController::setIOScheduler(const QVector<int>& pids, Process::IoPriorityClass priorityClass, int priority) ProcessController::Result ProcessController::setIOScheduler(const QVector<int>& pids, Process::IoPriorityClass priorityClass, int priority)
{ {
if (!d->localProcesses->supportsIoNiceness()) { if (!s_localProcesses->supportsIoNiceness()) {
return Result::Unsupported; return Result::Unsupported;
} }
...@@ -174,7 +169,7 @@ ProcessController::Result ProcessController::setIOScheduler(const QVector<int>& ...@@ -174,7 +169,7 @@ ProcessController::Result ProcessController::setIOScheduler(const QVector<int>&
} }
auto result = d->applyToPids(pids, [this, priorityClass, priority](int pid) { auto result = d->applyToPids(pids, [this, priorityClass, priority](int pid) {
return d->localProcesses->setIoNiceness(pid, priorityClass, priority); return s_localProcesses->setIoNiceness(pid, priorityClass, priority);
}); });
if (result.unchanged.isEmpty()) { if (result.unchanged.isEmpty()) {
return result.resultCode; return result.resultCode;
...@@ -221,12 +216,12 @@ ApplyResult KSysGuard::ProcessController::Private::applyToPids(const QVector<int ...@@ -221,12 +216,12 @@ ApplyResult KSysGuard::ProcessController::Private::applyToPids(const QVector<int
{ {
ApplyResult result; ApplyResult result;
localProcesses->errorCode = KSysGuard::Processes::Unknown; s_localProcesses->errorCode = KSysGuard::Processes::Unknown;
for (auto pid : pids) { for (auto pid : pids) {
auto success = function(pid); auto success = function(pid);
if (!success) { if (!success) {
switch (localProcesses->errorCode) { switch (s_localProcesses->errorCode) {
case KSysGuard::Processes::InsufficientPermissions: case KSysGuard::Processes::InsufficientPermissions:
case KSysGuard::Processes::Unknown: case KSysGuard::Processes::Unknown:
result.unchanged << pid; result.unchanged << pid;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment