aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiacomo Pozzoni <giacomopoz@gmail.com>2020-05-16 09:06:03 +0000
committerGitHub <noreply@github.com>2020-05-16 11:06:03 +0200
commitbd2d60c2676a1d7e843a2a5673b8216bad0768c7 (patch)
treedbbd0a226df2e7166a86b71269bfe4fa9f0a2171
parent8ad0ab362ee3e8ff5563d0ea3383d3d32969d27e (diff)
Fixes/3.3.5 aura infinite loop (#24631)
* Core/Auras: Attempt to fix infinite loop with aura 18950 on map unload * Core/Auras: Log a detailed error and assert when failing to remove all auras after a few tries * Code cleanup * Fix build warnings * Fix more build warnings
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp33
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp45
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp8
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h2
4 files changed, 69 insertions, 19 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 0001af2fc13..e2f509721ed 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -4130,7 +4130,7 @@ void Unit::RemoveAllAuras()
{
// this may be a dead loop if some events on aura remove will continiously apply aura on remove
// we want to have all auras removed, so use your brain when linking events
- while (!m_appliedAuras.empty() || !m_ownedAuras.empty())
+ for (int counter = 0; !m_appliedAuras.empty() || !m_ownedAuras.empty(); counter++)
{
AuraApplicationMap::iterator aurAppIter;
for (aurAppIter = m_appliedAuras.begin(); aurAppIter != m_appliedAuras.end();)
@@ -4139,6 +4139,37 @@ void Unit::RemoveAllAuras()
AuraMap::iterator aurIter;
for (aurIter = m_ownedAuras.begin(); aurIter != m_ownedAuras.end();)
RemoveOwnedAura(aurIter);
+
+ const int maxIteration = 50;
+ // give this loop a few tries, if there are still auras then log as much information as possible
+ if (counter >= maxIteration)
+ {
+ std::stringstream sstr;
+ sstr << "Unit::RemoveAllAuras() iterated " << maxIteration << " times already but there are still "
+ << m_appliedAuras.size() << " m_appliedAuras and " << m_ownedAuras.size() << " m_ownedAuras. Details:" << "\n";
+ sstr << GetDebugInfo() << "\n";
+
+ if (!m_appliedAuras.empty())
+ {
+ sstr << "m_appliedAuras:" << "\n";
+
+ for (std::pair<uint32 const, AuraApplication*>& auraAppPair : m_appliedAuras)
+ sstr << auraAppPair.second->GetDebugInfo() << "\n";
+ }
+
+ if (!m_ownedAuras.empty())
+ {
+ sstr << "m_ownedAuras:" << "\n";
+
+ for (std::pair<uint32 const, Aura*>& auraPair : m_ownedAuras)
+ sstr << auraPair.second->GetDebugInfo() << "\n";
+ }
+
+ TC_LOG_ERROR("entities.unit", "%s", sstr.str().c_str());
+ ABORT_MSG("%s", sstr.str().c_str());
+
+ break;
+ }
}
}
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 02975f501dc..d331de21634 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -1349,8 +1349,9 @@ void AuraEffect::HandleModInvisibilityDetect(AuraApplication const* aurApp, uint
target->m_invisibilityDetect.AddValue(type, -GetAmount());
}
- // call functions which may have additional effects after chainging state of unit
- target->UpdateObjectVisibility();
+ // call functions which may have additional effects after changing state of unit
+ if (target->IsInWorld())
+ target->UpdateObjectVisibility();
}
void AuraEffect::HandleModInvisibility(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -1400,13 +1401,15 @@ void AuraEffect::HandleModInvisibility(AuraApplication const* aurApp, uint8 mode
target->m_invisibility.AddValue(type, -GetAmount());
}
- // call functions which may have additional effects after chainging state of unit
+ // call functions which may have additional effects after changing state of unit
if (apply && (mode & AURA_EFFECT_HANDLE_REAL))
{
// drop flag at invisibiliy in bg
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
}
- target->UpdateObjectVisibility();
+
+ if (target->IsInWorld())
+ target->UpdateObjectVisibility();
}
void AuraEffect::HandleModStealthDetect(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -1430,8 +1433,9 @@ void AuraEffect::HandleModStealthDetect(AuraApplication const* aurApp, uint8 mod
target->m_stealthDetect.AddValue(type, -GetAmount());
}
- // call functions which may have additional effects after chainging state of unit
- target->UpdateObjectVisibility();
+ // call functions which may have additional effects after changing state of unit
+ if (target->IsInWorld())
+ target->UpdateObjectVisibility();
}
void AuraEffect::HandleModStealth(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -1465,13 +1469,15 @@ void AuraEffect::HandleModStealth(AuraApplication const* aurApp, uint8 mode, boo
}
}
- // call functions which may have additional effects after chainging state of unit
+ // call functions which may have additional effects after changing state of unit
if (apply && (mode & AURA_EFFECT_HANDLE_REAL))
{
// drop flag at stealth in bg
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
}
- target->UpdateObjectVisibility();
+
+ if (target->IsInWorld())
+ target->UpdateObjectVisibility();
}
void AuraEffect::HandleModStealthLevel(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -1487,8 +1493,9 @@ void AuraEffect::HandleModStealthLevel(AuraApplication const* aurApp, uint8 mode
else
target->m_stealth.AddValue(type, -GetAmount());
- // call functions which may have additional effects after chainging state of unit
- target->UpdateObjectVisibility();
+ // call functions which may have additional effects after changing state of unit
+ if (target->IsInWorld())
+ target->UpdateObjectVisibility();
}
void AuraEffect::HandleDetectAmore(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -1543,7 +1550,7 @@ void AuraEffect::HandleSpiritOfRedemption(AuraApplication const* aurApp, uint8 m
}
// die at aura end
else if (target->IsAlive())
- // call functions which may have additional effects after chainging state of unit
+ // call functions which may have additional effects after changing state of unit
target->setDeathState(JUST_DIED);
}
@@ -1612,7 +1619,7 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app
target->SetPhaseMask(newPhase, false);
}
- // call functions which may have additional effects after chainging state of unit
+ // call functions which may have additional effects after changing state of unit
// phase auras normally not expected at BG but anyway better check
if (apply)
{
@@ -2253,7 +2260,7 @@ void AuraEffect::HandleModUnattackable(AuraApplication const* aurApp, uint8 mode
target->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE_2, apply);
- // call functions which may have additional effects after chainging state of unit
+ // call functions which may have additional effects after changing state of unit
if (apply && (mode & AURA_EFFECT_HANDLE_REAL))
{
if (target->GetMap()->IsDungeon())
@@ -2345,7 +2352,7 @@ void AuraEffect::HandleAuraModSilence(AuraApplication const* aurApp, uint8 mode,
{
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED);
- // call functions which may have additional effects after chainging state of unit
+ // call functions which may have additional effects after changing state of unit
// Stop cast only spells vs PreventionType == SPELL_PREVENTION_TYPE_SILENCE
for (uint32 i = CURRENT_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i)
if (Spell* spell = target->GetCurrentSpell(CurrentSpellTypes(i)))
@@ -2500,8 +2507,9 @@ void AuraEffect::HandleAuraModStalked(AuraApplication const* aurApp, uint8 mode,
target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT);
}
- // call functions which may have additional effects after chainging state of unit
- target->UpdateObjectVisibility();
+ // call functions which may have additional effects after changing state of unit
+ if (target->IsInWorld())
+ target->UpdateObjectVisibility();
}
void AuraEffect::HandleAuraUntrackable(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -4943,8 +4951,9 @@ void AuraEffect::HandleAuraModFakeInebriation(AuraApplication const* aurApp, uin
target->m_invisibilityDetect.DelFlag(INVISIBILITY_DRUNK);
}
- // call functions which may have additional effects after chainging state of unit
- target->UpdateObjectVisibility();
+ // call functions which may have additional effects after changing state of unit
+ if (target->IsInWorld())
+ target->UpdateObjectVisibility();
}
void AuraEffect::HandleAuraOverrideSpells(AuraApplication const* aurApp, uint8 mode, bool apply) const
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 94dc12f0b23..6c61ade3373 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -262,6 +262,14 @@ void AuraApplication::ClientUpdate(bool remove)
_target->SendMessageToSet(&data, true);
}
+std::string AuraApplication::GetDebugInfo() const
+{
+ std::stringstream sstr;
+ sstr << "Base: " << (GetBase() ? GetBase()->GetDebugInfo() : "NULL")
+ << "\nTarget: " << (GetTarget() ? GetTarget()->GetDebugInfo() : "NULL");
+ return sstr.str();
+}
+
uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 availableEffectMask, WorldObject* owner)
{
ASSERT_NODEBUGINFO(spellProto);
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index e57813b0e1e..86da73a2263 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -82,6 +82,8 @@ class TC_GAME_API AuraApplication
bool IsNeedClientUpdate() const { return _needClientUpdate;}
void BuildUpdatePacket(ByteBuffer& data, bool remove) const;
void ClientUpdate(bool remove = false);
+
+ std::string GetDebugInfo() const;
};
// Caches some information about caster (because it may no longer exist)