[9388] Implement max cast chain length for triggered spells.

* New config option MaxSpellCastsInChain ( 0 is disabled old way work )
* Check added for prevent stack overflow crashes in case infinity triggered casts sequences
  with more useful error output instead crash.
* Default config steeing in 10 casts expected to allow all possible in game proper cast chains.
This commit is contained in:
VladimirMangos 2010-02-15 12:10:08 +03:00
parent 574f396b0d
commit 58d188f21a
7 changed files with 45 additions and 1 deletions

View file

@ -2522,6 +2522,19 @@ void Spell::cast(bool skipCheck)
{
SetExecutedCurrently(true);
if (!m_caster->CheckAndIncreaseCastCounter())
{
if (m_triggeredByAuraSpell)
sLog.outError("Spell %u triggered by aura spell %u too deep in cast chain for cast. Cast not allowed for prevent overflow stack crash.");
else
sLog.outError("Spell %u too deep in cast chain for cast. Cast not allowed for prevent overflow stack crash.");
SendCastResult(SPELL_FAILED_ERROR);
finish(false);
SetExecutedCurrently(false);
return;
}
// update pointers base at GUIDs to prevent access to non-existed already object
UpdatePointers();
@ -2529,6 +2542,7 @@ void Spell::cast(bool skipCheck)
if(!m_targets.getUnitTarget() && m_targets.getUnitTargetGUID() && m_targets.getUnitTargetGUID() != m_caster->GetGUID())
{
cancel();
m_caster->DecreaseCastCounter();
SetExecutedCurrently(false);
return;
}
@ -2541,6 +2555,7 @@ void Spell::cast(bool skipCheck)
{
SendCastResult(castResult);
finish(false);
m_caster->DecreaseCastCounter();
SetExecutedCurrently(false);
return;
}
@ -2553,6 +2568,7 @@ void Spell::cast(bool skipCheck)
{
SendCastResult(castResult);
finish(false);
m_caster->DecreaseCastCounter();
SetExecutedCurrently(false);
return;
}
@ -2667,6 +2683,7 @@ void Spell::cast(bool skipCheck)
if(m_spellState == SPELL_STATE_FINISHED) // stop cast if spell marked as finish somewhere in FillTargetMap
{
m_caster->DecreaseCastCounter();
SetExecutedCurrently(false);
return;
}
@ -2699,6 +2716,7 @@ void Spell::cast(bool skipCheck)
handle_immediate();
}
m_caster->DecreaseCastCounter();
SetExecutedCurrently(false);
}

View file

@ -208,6 +208,8 @@ Unit::Unit()
for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
m_currentSpells[i] = NULL;
m_castCounter = 0;
m_addDmgOnce = 0;
for(int i = 0; i < MAX_TOTEM; ++i)
@ -13435,3 +13437,14 @@ void Unit::CleanupDeletedAuras()
delete *itr;
m_deletedAuras.clear();
}
bool Unit::CheckAndIncreaseCastCounter()
{
uint32 maxCasts = sWorld.getConfig(CONFIG_MAX_SPELL_CASTS_IN_CHAIN);
if (maxCasts && m_castCounter >= maxCasts)
return false;
++m_castCounter;
return true;
}

View file

@ -1520,6 +1520,9 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
Spell* GetCurrentSpell(CurrentSpellTypes spellType) const { return m_currentSpells[spellType]; }
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
bool CheckAndIncreaseCastCounter();
void DecreaseCastCounter() { if (m_castCounter) --m_castCounter; }
uint32 m_addDmgOnce;
uint64 m_TotemSlot[MAX_TOTEM];
uint64 m_ObjectSlot[4];
@ -1848,6 +1851,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
uint32 m_CombatTimer;
Spell* m_currentSpells[CURRENT_MAX_SPELL];
uint32 m_castCounter; // count casts chain of triggered spells for prevent infinity cast crashes
UnitVisibility m_Visibility;

View file

@ -795,6 +795,8 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_INSTANCE_IGNORE_RAID] = sConfig.GetBoolDefault("Instance.IgnoreRaid", false);
m_configs[CONFIG_CAST_UNSTUCK] = sConfig.GetBoolDefault("CastUnstuck", true);
m_configs[CONFIG_MAX_SPELL_CASTS_IN_CHAIN] = sConfig.GetIntDefault("MaxSpellCastsInChain", 10);
m_configs[CONFIG_INSTANCE_RESET_TIME_HOUR] = sConfig.GetIntDefault("Instance.ResetTimeHour", 4);
m_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfig.GetIntDefault("Instance.UnloadDelay", 30 * MINUTE * IN_MILISECONDS);

View file

@ -127,6 +127,7 @@ enum WorldConfigs
CONFIG_INSTANCE_RESET_TIME_HOUR,
CONFIG_INSTANCE_UNLOAD_DELAY,
CONFIG_CAST_UNSTUCK,
CONFIG_MAX_SPELL_CASTS_IN_CHAIN,
CONFIG_MAX_PRIMARY_TRADE_SKILL,
CONFIG_MIN_PETITION_SIGNS,
CONFIG_GM_LOGIN_STATE,

View file

@ -508,6 +508,12 @@ LogColors = ""
# Default: 1 (true)
# 0 (false)
#
# MaxSpellCastsInChain
# Max amount triggered spell casts in chain by one caster, prevent stack overflow crash
# Too Low value will make some correct triggered casts fail
# 0 (no limit)
# Default: 10
#
# Instance.IgnoreLevel
# Ignore level requirement to enter instance
# Default: 0 (false)

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "9387"
#define REVISION_NR "9388"
#endif // __REVISION_NR_H__