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

(cherry picked from commit bd2d60c267)
This commit is contained in:
Giacomo Pozzoni
2020-05-16 09:06:03 +00:00
committed by Shauren
parent 2256735a77
commit 9cb01a7904
4 changed files with 68 additions and 18 deletions

View File

@@ -4035,7 +4035,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();)
@@ -4044,6 +4044,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;
}
}
}

View File

@@ -1406,8 +1406,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
@@ -1457,13 +1458,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(SpellAuraInterruptFlags::StealthOrInvis);
}
target->UpdateObjectVisibility();
if (target->IsInWorld())
target->UpdateObjectVisibility();
}
void AuraEffect::HandleModStealthDetect(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -1487,8 +1490,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
@@ -1522,13 +1526,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(SpellAuraInterruptFlags::StealthOrInvis);
}
target->UpdateObjectVisibility();
if (target->IsInWorld())
target->UpdateObjectVisibility();
}
void AuraEffect::HandleModStealthLevel(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -1544,8 +1550,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
@@ -1604,7 +1611,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);
}
@@ -2164,7 +2171,7 @@ void AuraEffect::HandleModUnattackable(AuraApplication const* aurApp, uint8 mode
else
target->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE_2);
// 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())
@@ -2261,7 +2268,7 @@ void AuraEffect::HandleAuraModSilence(AuraApplication const* aurApp, uint8 mode,
{
target->AddUnitFlag(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)))
@@ -2409,8 +2416,9 @@ void AuraEffect::HandleAuraModStalked(AuraApplication const* aurApp, uint8 mode,
target->RemoveDynamicFlag(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
@@ -5051,8 +5059,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

View File

@@ -291,6 +291,14 @@ void AuraApplication::ClientUpdate(bool remove)
_target->SendMessageToSet(update.Write(), true);
}
std::string AuraApplication::GetDebugInfo() const
{
std::stringstream sstr;
sstr << "Base: " << (GetBase() ? GetBase()->GetDebugInfo() : "NULL")
<< "\nTarget: " << (GetTarget() ? GetTarget()->GetDebugInfo() : "NULL");
return sstr.str();
}
uint32 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint32 availableEffectMask, WorldObject* owner)
{
ASSERT_NODEBUGINFO(spellProto);

View File

@@ -92,6 +92,8 @@ class TC_GAME_API AuraApplication
bool IsNeedClientUpdate() const { return _needClientUpdate; }
void BuildUpdatePacket(WorldPackets::Spells::AuraInfo& auraInfo, bool remove);
void ClientUpdate(bool remove = false);
std::string GetDebugInfo() const;
};
// Structure representing database aura primary key fields