From dbed818f6fe435a02d10f110e2c0883a53330230 Mon Sep 17 00:00:00 2001 From: jackpoz Date: Sat, 8 Feb 2014 21:57:28 +0100 Subject: Core/SAI: Fix crash Disable script type SMART_SCRIPT_TYPE_TIMED_ACTIONLIST actions if they are trying to overwrite the timed action list while iterating it. This was invalidating the iterator and deleting any smart action stored in it, including the current executed one. Valgrind log: Invalid read of size 1 at SmartScript::OnUpdate(unsigned int) (SmartScript.cpp:3258) by SmartAI::UpdateAI(unsigned int) (SmartAI.cpp:331) by Creature::Update(unsigned int) (Creature.cpp:544) Address 0x1807d9b2 is 10 bytes after a block of size 40 alloc'd at operator new(unsigned long) (vg_replace_malloc.c:319) ... by SmartAIMgr::LoadSmartAIFromDB() (SmartScriptMgr.cpp:231) by World::SetInitialWorldSettings() (World.cpp:1724) by Master::Run() (Master.cpp:169) by main (Main.cpp:142) --- src/server/game/AI/SmartScripts/SmartScript.cpp | 12 ++++++++++++ src/server/game/AI/SmartScripts/SmartScript.h | 1 + 2 files changed, 13 insertions(+) (limited to 'src') diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index bd51fe0a85b..49beb0ae86f 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -76,6 +76,7 @@ SmartScript::SmartScript() goOrigGUID = 0; mLastInvoker = 0; mScriptType = SMART_SCRIPT_TYPE_CREATURE; + isProcessingTimedActionList = false; } SmartScript::~SmartScript() @@ -3253,6 +3254,7 @@ void SmartScript::OnUpdate(uint32 const diff) bool needCleanup = true; if (!mTimedActionList.empty()) { + isProcessingTimedActionList = true; for (SmartAIEventList::iterator i = mTimedActionList.begin(); i != mTimedActionList.end(); ++i) { if ((*i).enableTimed) @@ -3261,6 +3263,8 @@ void SmartScript::OnUpdate(uint32 const diff) needCleanup = false; } } + + isProcessingTimedActionList = false; } if (needCleanup) mTimedActionList.clear(); @@ -3502,6 +3506,14 @@ Unit* SmartScript::DoFindClosestFriendlyInRange(float range, bool playerOnly) void SmartScript::SetScript9(SmartScriptHolder& e, uint32 entry) { + //do NOT clear mTimedActionList if it's being iterated because it will invalidate the iterator and delete + // any SmartScriptHolder contained like the "e" parameter passed to this function + if (isProcessingTimedActionList) + { + TC_LOG_ERROR("scripts.ai", "Entry %d SourceType %u Event %u Action %u is trying to overwrite timed action list from a timed action, this is not allowed!.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType()); + return; + } + mTimedActionList.clear(); mTimedActionList = sSmartScriptMgr->GetScript(entry, SMART_SCRIPT_TYPE_TIMED_ACTIONLIST); if (mTimedActionList.empty()) diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 2e1068d1bff..861da6d86d2 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -222,6 +222,7 @@ class SmartScript SmartAIEventList mEvents; SmartAIEventList mInstallEvents; SmartAIEventList mTimedActionList; + bool isProcessingTimedActionList; Creature* me; uint64 meOrigGUID; GameObject* go; -- cgit v1.2.3