Skip to content

Commit

Permalink
Fix access-after-delete during enbtity script engine cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
ksuprynowicz committed Nov 14, 2024
1 parent ad5b6d0 commit fe82904
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 4 deletions.
10 changes: 10 additions & 0 deletions libraries/script-engine/src/v8/ScriptEngineDebugFlags.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//
// Created by ksuprynowicz on 14.11.24.
//

#ifndef OVERTE_SCRIPTENGINEDEBUGFLAGS_H
#define OVERTE_SCRIPTENGINEDEBUGFLAGS_H

#define OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD

#endif //OVERTE_SCRIPTENGINEDEBUGFLAGS_H
11 changes: 9 additions & 2 deletions libraries/script-engine/src/v8/ScriptEngineV8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,13 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager *manager) : ScriptEngine(manager),
}

ScriptEngineV8::~ScriptEngineV8() {
// Process remaining events to avoid problems with `deleteLater` calling destructor of script proxies after script engine has been deleted:
{
QEventLoop loop;
loop.processEvents();
}
// This is necessary for script engines that don't run in ScriptManager::run(), for example entity scripts:
disconnectSignalProxies();
deleteUnusedValueWrappers();
#ifdef OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD
_wasDestroyed = true;
Expand All @@ -272,14 +279,14 @@ void ScriptEngineV8::perManagerLoopIterationCleanup() {
void ScriptEngineV8::disconnectSignalProxies() {
_signalProxySetLock.lockForRead();
while (!_signalProxySet.empty()) {
auto proxy = *_signalProxySet.begin();
_signalProxySetLock.unlock();
delete *_signalProxySet.begin();
delete proxy;
_signalProxySetLock.lockForRead();
}
_signalProxySetLock.unlock();
}


void ScriptEngineV8::deleteUnusedValueWrappers() {
while (!_scriptValueWrappersToDelete.empty()) {
auto wrapper = _scriptValueWrappersToDelete.dequeue();
Expand Down
3 changes: 1 addition & 2 deletions libraries/script-engine/src/v8/ScriptEngineV8.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "libplatform/libplatform.h"
#include "v8.h"

#include "ScriptEngineDebugFlags.h"
#include "../ScriptEngine.h"
#include "../ScriptManager.h"
#include "../ScriptException.h"
Expand All @@ -58,8 +59,6 @@ using ScriptContextV8Pointer = std::shared_ptr<ScriptContextV8Wrapper>;

const double GARBAGE_COLLECTION_TIME_LIMIT_S = 1.0;

#define OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD

Q_DECLARE_METATYPE(ScriptEngine::FunctionSignature)

/// [V8] Implements ScriptEngine for V8 and translates calls for QScriptEngine
Expand Down
2 changes: 2 additions & 0 deletions libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1217,7 +1217,9 @@ ScriptSignalV8Proxy::~ScriptSignalV8Proxy() {
_objectLifetime.Reset();
_v8Context.Reset();
#ifdef OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD
Q_ASSERT(!_wasDeleted);
Q_ASSERT(!_engine->_wasDestroyed);
_wasDeleted = true;
#endif
_engine->_signalProxySetLock.lockForWrite();
_engine->_signalProxySet.remove(this);
Expand Down
4 changes: 4 additions & 0 deletions libraries/script-engine/src/v8/ScriptObjectV8Proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <QtCore/QPointer>
#include <QtCore/QString>

#include "ScriptEngineDebugFlags.h"
#include "../ScriptEngine.h"
#include "../Scriptable.h"
#include "ScriptEngineV8.h"
Expand Down Expand Up @@ -295,6 +296,9 @@ class ScriptSignalV8Proxy final : public ScriptSignalV8ProxyBase, public ReadWri
// Call counter for debugging purposes. It can be used to determine which signals are overwhelming script engine.
int _callCounter{0};
float _totalCallTime_s{ 0.0 };
#ifdef OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD
std::atomic<bool> _wasDeleted{false};
#endif

Q_DISABLE_COPY(ScriptSignalV8Proxy)
};
Expand Down

0 comments on commit fe82904

Please sign in to comment.