Fix access-after-delete on leaving domain with entity scripts

This commit is contained in:
Karol Suprynowicz 2024-11-10 00:48:05 +01:00
parent ac20b34af9
commit fe4a097d01
4 changed files with 14 additions and 3 deletions

View file

@ -567,6 +567,7 @@ void EntityScriptServer::addingEntity(const EntityItemID& entityID) {
void EntityScriptServer::deletingEntity(const EntityItemID& entityID) { void EntityScriptServer::deletingEntity(const EntityItemID& entityID) {
if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptManager) { if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptManager) {
// TODO: Check if this is running on script engine thread, otherwise lambda capturing script engine pointer is needed
_entitiesScriptManager->unloadEntityScript(entityID, true); _entitiesScriptManager->unloadEntityScript(entityID, true);
} }
} }
@ -584,6 +585,7 @@ void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, bool
EntityScriptDetails details; EntityScriptDetails details;
bool isRunning = _entitiesScriptManager->getEntityScriptDetails(entityID, details); bool isRunning = _entitiesScriptManager->getEntityScriptDetails(entityID, details);
if (entity && (forceRedownload || !isRunning || details.scriptText != entity->getServerScripts())) { if (entity && (forceRedownload || !isRunning || details.scriptText != entity->getServerScripts())) {
// TODO: Check if this is running on script engine thread, otherwise lambda capturing script engine pointer is needed
if (isRunning) { if (isRunning) {
_entitiesScriptManager->unloadEntityScript(entityID, true); _entitiesScriptManager->unloadEntityScript(entityID, true);
} }

View file

@ -288,7 +288,10 @@ void EntityTreeRenderer::stopDomainAndNonOwnedEntities() {
EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID); EntityItemPointer entityItem = getTree()->findEntityByEntityItemID(entityID);
if (entityItem && !entityItem->getScript().isEmpty()) { if (entityItem && !entityItem->getScript().isEmpty()) {
if (!(entityItem->isLocalEntity() || entityItem->isMyAvatarEntity())) { if (!(entityItem->isLocalEntity() || entityItem->isMyAvatarEntity())) {
_nonPersistentEntitiesScriptManager->unloadEntityScript(entityID, true); auto scriptEnginePtr = _nonPersistentEntitiesScriptManager;
QMetaObject::invokeMethod(scriptEnginePtr.get(), [scriptEnginePtr, entityID]{
scriptEnginePtr->unloadEntityScript(entityID, true);
});
} }
} }
} }
@ -1110,7 +1113,9 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
if (_currentEntitiesInside.contains(entityID)) { if (_currentEntitiesInside.contains(entityID)) {
scriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); scriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
} }
scriptEngine->unloadEntityScript(entityID, true); QMetaObject::invokeMethod(scriptEngine.get(), [scriptEngine, entityID]{
scriptEngine->unloadEntityScript(entityID, true);
});
} }
auto scene = _viewState->getMain3DScene(); auto scene = _viewState->getMain3DScene();
@ -1163,7 +1168,9 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, bool
if (_currentEntitiesInside.contains(entityID)) { if (_currentEntitiesInside.contains(entityID)) {
scriptEngine->callEntityScriptMethod(entityID, "leaveEntity"); scriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
} }
scriptEngine->unloadEntityScript(entityID); QMetaObject::invokeMethod(scriptEngine.get(), [scriptEngine, entityID]{
scriptEngine->unloadEntityScript(entityID);
});
} }
entity->scriptHasUnloaded(); entity->scriptHasUnloaded();
} }

View file

@ -381,6 +381,7 @@ ScriptManager::~ScriptManager() {
if (_type == ScriptManager::Type::ENTITY_CLIENT) { if (_type == ScriptManager::Type::ENTITY_CLIENT) {
printf("ScriptManager::~ScriptManager"); printf("ScriptManager::~ScriptManager");
} }
_isDeleted = true;
} }
void ScriptManager::disconnectNonEssentialSignals() { void ScriptManager::disconnectNonEssentialSignals() {

View file

@ -1665,6 +1665,7 @@ protected:
friend ScriptManagerPointer newScriptManager(Context context, const QString& scriptContents, const QString& fileNameString); friend ScriptManagerPointer newScriptManager(Context context, const QString& scriptContents, const QString& fileNameString);
friend class ScriptManagerScriptingInterface; friend class ScriptManagerScriptingInterface;
std::atomic<bool> _isDeleted {false}; // This is used for debugging use-after-delete. It happens quite often, so I'm keeping it here for now.
}; };
/** /**