From ece2b8096b1305c528ca3079a47c5c55a33b88ea Mon Sep 17 00:00:00 2001 From: ksuprynowicz <ksuprynowicz@post.pl> Date: Fri, 12 Aug 2022 00:39:45 +0200 Subject: [PATCH] Fixed list item removal during access bug --- .../src/qtscript/ScriptObjectQtProxy.cpp | 43 +++++++++++++------ .../src/qtscript/ScriptObjectQtProxy.h | 5 ++- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp index 7f09479ee4..e8b7f33c7e 100644 --- a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp +++ b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.cpp @@ -4,6 +4,7 @@ // // Created by Heather Anderson on 12/5/21. // Copyright 2021 Vircadia contributors. +// Copyright 2022 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -588,12 +589,19 @@ int ScriptSignalQtProxy::qt_metacall(QMetaObject::Call call, int id, void** argu QVariant argValue(methodArgTypeId, arguments[arg+1]); args.append(_engine->castVariantToValue(argValue)); } - - for (ConnectionList::iterator iter = _connections.begin(); iter != _connections.end(); ++iter) { + + QList<Connection> connections; + withReadLock([&]{ + for (ConnectionList::iterator iter = _connections.begin(); iter != _connections.end(); ++iter) { + connections.push_back(*iter); + } + }); + + for (ConnectionList::iterator iter = connections.begin(); iter != connections.end(); ++iter) { Connection& conn = *iter; - conn.callback.call(conn.thisValue, args); + conn.callback.call(conn.thisValue, args); } - + return -1; } @@ -602,15 +610,17 @@ int ScriptSignalQtProxy::discoverMetaCallIdx() { return ourMeta->methodCount(); } -ScriptSignalQtProxy::ConnectionList::iterator ScriptSignalQtProxy::findConnection(QScriptValue thisObject, - QScriptValue callback) { - for (ConnectionList::iterator iter = _connections.begin(); iter != _connections.end(); ++iter) { - Connection& conn = *iter; - if (conn.callback.strictlyEquals(callback) && conn.thisValue.strictlyEquals(thisObject)) { - return iter; +ScriptSignalQtProxy::ConnectionList::iterator ScriptSignalQtProxy::findConnection(QScriptValue thisObject, QScriptValue callback) { + ConnectionList::iterator iter; + withReadLock([&]{ + for (iter = _connections.begin(); iter != _connections.end(); ++iter) { + Connection& conn = *iter; + if (conn.callback.strictlyEquals(callback) && conn.thisValue.strictlyEquals(thisObject)) { + break; + } } - } - return _connections.end(); + }); + return iter; } @@ -660,7 +670,10 @@ void ScriptSignalQtProxy::connect(QScriptValue arg0, QScriptValue arg1) { Connection newConn; newConn.callback = callback; newConn.thisValue = callbackThis; - _connections.append(newConn); + + withWriteLock([&]{ + _connections.append(newConn); + }); // inform Qt that we're connecting to this signal if (!_isConnected) { @@ -700,7 +713,9 @@ void ScriptSignalQtProxy::disconnect(QScriptValue arg0, QScriptValue arg1) { } // remove it from our internal list of connections - _connections.erase(lookup); + withReadLock([&]{ + _connections.erase(lookup); + }); // remove a reference to ourselves from the destination callback QScriptValue destData = callback.data(); diff --git a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h index 34ee852611..aa23595627 100644 --- a/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h +++ b/libraries/script-engine/src/qtscript/ScriptObjectQtProxy.h @@ -4,6 +4,7 @@ // // Created by Heather Anderson on 12/5/21. // Copyright 2021 Vircadia contributors. +// Copyright 2022 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -28,6 +29,8 @@ #include "../ScriptEngine.h" #include "ScriptEngineQtScript.h" +#include <shared/ReadWriteLockable.h> + class ScriptEngineQtScript; class ScriptSignalQtProxy; @@ -171,7 +174,7 @@ public: // API Q_INVOKABLE virtual void disconnect(QScriptValue arg0, QScriptValue arg1 = QScriptValue()) = 0; }; -class ScriptSignalQtProxy final : public ScriptSignalQtProxyBase { +class ScriptSignalQtProxy final : public ScriptSignalQtProxyBase, public ReadWriteLockable { private: // storage struct Connection { QScriptValue thisValue;