[scripting] Avoid threading issues when loading from a file

Summary:
KWin::Script::loadScriptFromFile ran in it's own thread and accessed
member variables of KWin::Script without any guards.

Potentially script could be destroyed whilst the file is loading.

Rather than adding mutexes everywhere, this patch scopes the QFile
object to be local to the threaded function making it independent.

BUG: 403038

Test Plan: Ran a script from a file

Reviewers: #kwin, graesslin

Reviewed By: #kwin, graesslin

Subscribers: kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D18126
This commit is contained in:
David Edmundson 2019-01-09 19:40:09 +00:00
parent fbe219172a
commit ba7aecfe53
2 changed files with 11 additions and 14 deletions

View file

@ -231,9 +231,9 @@ KWin::AbstractScript::AbstractScript(int id, QString scriptName, QString pluginN
: QObject(parent)
, m_scriptId(id)
, m_pluginName(pluginName)
, m_fileName(scriptName)
, m_running(false)
{
m_scriptFile.setFileName(scriptName);
if (m_pluginName.isNull()) {
m_pluginName = scriptName;
}
@ -255,7 +255,7 @@ void KWin::AbstractScript::stop()
void KWin::AbstractScript::printMessage(const QString &message)
{
qCDebug(KWIN_SCRIPTING) << scriptFile().fileName() << ":" << message;
qCDebug(KWIN_SCRIPTING) << fileName() << ":" << message;
emit print(message);
}
@ -468,16 +468,16 @@ void KWin::Script::run()
m_starting = true;
QFutureWatcher<QByteArray> *watcher = new QFutureWatcher<QByteArray>(this);
connect(watcher, SIGNAL(finished()), SLOT(slotScriptLoadedFromFile()));
watcher->setFuture(QtConcurrent::run(this, &KWin::Script::loadScriptFromFile));
watcher->setFuture(QtConcurrent::run(this, &KWin::Script::loadScriptFromFile, fileName()));
}
QByteArray KWin::Script::loadScriptFromFile()
QByteArray KWin::Script::loadScriptFromFile(const QString &fileName)
{
if (!scriptFile().open(QIODevice::ReadOnly)) {
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
return QByteArray();
}
QByteArray result(scriptFile().readAll());
scriptFile().close();
QByteArray result(file.readAll());
return result;
}
@ -591,7 +591,7 @@ void KWin::DeclarativeScript::run()
return;
}
m_component->loadUrl(QUrl::fromLocalFile(scriptFile().fileName()));
m_component->loadUrl(QUrl::fromLocalFile(fileName()));
if (m_component->isLoading()) {
connect(m_component, &QQmlComponent::statusChanged, this, &DeclarativeScript::createComponent);
} else {

View file

@ -60,7 +60,7 @@ public:
AbstractScript(int id, QString scriptName, QString pluginName, QObject *parent = nullptr);
~AbstractScript();
QString fileName() const {
return m_scriptFile.fileName();
return m_fileName;
}
const QString &pluginName() {
return m_pluginName;
@ -153,9 +153,6 @@ Q_SIGNALS:
void runningChanged(bool);
protected:
QFile &scriptFile() {
return m_scriptFile;
}
bool running() const {
return m_running;
}
@ -204,7 +201,7 @@ private:
**/
QAction *createMenu(const QString &title, QScriptValue &items, QMenu *parent);
int m_scriptId;
QFile m_scriptFile;
QString m_fileName;
QString m_pluginName;
bool m_running;
QHash<QAction*, QScriptValue> m_shortcutCallbacks;
@ -255,7 +252,7 @@ private:
* Read the script from file into a byte array.
* If file cannot be read an empty byte array is returned.
**/
QByteArray loadScriptFromFile();
QByteArray loadScriptFromFile(const QString &fileName);
QScriptEngine *m_engine;
bool m_starting;
QScopedPointer<ScriptUnloaderAgent> m_agent;