aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2023-06-29 11:39:02 +0200
committerShauren <shauren.trinity@gmail.com>2023-06-29 11:39:02 +0200
commit29eac37a16df2ec14cba89f4d6e28f54ca1a4e25 (patch)
tree0e340300bd3e1e0aaf8ff27324434b59f6a3e2d2 /src/server/game/Entities
parentbacfbec25180cd0a02fec20e788d74e2fcaf1a0c (diff)
Core/Spells: Fully prevent infinite proc loops and add logging to detect most spells that could possibly trigger this behavior at startup
Closes #28865
Diffstat (limited to 'src/server/game/Entities')
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp14
-rw-r--r--src/server/game/Entities/Unit/Unit.h4
2 files changed, 16 insertions, 2 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index cd97d0d4081..46b0f9bc681 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -303,7 +303,7 @@ SpellNonMeleeDamage::SpellNonMeleeDamage(Unit* _attacker, Unit* _target, SpellIn
Unit::Unit(bool isWorldObject) :
WorldObject(isWorldObject), m_lastSanctuaryTime(0), LastCharmerGUID(), movespline(new Movement::MoveSpline()),
- m_ControlledByPlayer(false), m_procDeep(0), m_transformSpell(0),
+ m_ControlledByPlayer(false), m_procDeep(0), m_procChainLength(0), m_transformSpell(0),
m_removedAurasCount(0), m_interruptMask(SpellAuraInterruptFlags::None), m_interruptMask2(SpellAuraInterruptFlags2::None),
m_unitMovedByMe(nullptr), m_playerMovingMe(nullptr), m_charmer(nullptr), m_charmed(nullptr),
i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_vehicle(nullptr),
@@ -5320,6 +5320,13 @@ void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const* log)
ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask,
Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
{
+ static constexpr int32 ProcChainHardLimit = 10;
+ if (spell && spell->GetProcChainLength() >= ProcChainHardLimit)
+ {
+ TC_LOG_ERROR("spells.aura.effect", "Unit::ProcSkillsAndAuras: Possible infinite proc loop detected, current triggering spell {}", spell->GetDebugInfo().c_str());
+ return;
+ }
+
WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK;
if (typeMaskActor && actor)
actor->ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
@@ -10020,6 +10027,9 @@ void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProc
{
Spell const* triggeringSpell = eventInfo.GetProcSpell();
bool const disableProcs = triggeringSpell && triggeringSpell->IsProcDisabled();
+
+ int32 oldProcChainLength = std::exchange(m_procChainLength, std::max(m_procChainLength + 1, triggeringSpell ? triggeringSpell->GetProcChainLength() : 0));
+
if (disableProcs)
SetCantProc(true);
@@ -10033,6 +10043,8 @@ void Unit::TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProc
if (disableProcs)
SetCantProc(false);
+
+ m_procChainLength = oldProcChainLength;
}
///----------Pet responses methods-----------------
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index e01d32067e5..0f63cc369a9 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1803,6 +1803,7 @@ class TC_GAME_API Unit : public WorldObject
// proc trigger system
bool CanProc() const { return !m_procDeep; }
void SetCantProc(bool apply);
+ int32 GetProcChainLength() const { return m_procChainLength; }
uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId) const;
@@ -1950,7 +1951,8 @@ class TC_GAME_API Unit : public WorldObject
DeathState m_deathState;
- int32 m_procDeep;
+ int32 m_procDeep; // tracked for proc system correctness (what spells should proc what)
+ int32 m_procChainLength; // tracked to protect against infinite proc loops (hard limit, will disallow procs even if they should happen)
typedef std::list<DynamicObject*> DynObjectList;
DynObjectList m_dynObj;