Core/Spells: Added additional validation to loading spell_linked_spell to prevent infinite loops

Closes #28753
This commit is contained in:
Shauren
2023-01-15 13:30:17 +01:00
parent 7587cff0dc
commit badb55bfd9
4 changed files with 39 additions and 22 deletions

View File

@@ -1357,7 +1357,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
// apply linked auras
if (apply)
{
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(GetId() + SPELL_LINK_AURA))
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_AURA, GetId()))
{
for (std::vector<int32>::const_iterator itr = spellTriggered->begin(); itr != spellTriggered->end(); ++itr)
{
@@ -1371,7 +1371,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
else
{
// remove linked auras
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(-(int32)GetId()))
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_REMOVE, GetId()))
{
for (std::vector<int32>::const_iterator itr = spellTriggered->begin(); itr != spellTriggered->end(); ++itr)
{
@@ -1383,7 +1383,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
.SetOriginalCastId(GetCastId()));
}
}
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(GetId() + SPELL_LINK_AURA))
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_AURA, GetId()))
{
for (std::vector<int32>::const_iterator itr = spellTriggered->begin(); itr != spellTriggered->end(); ++itr)
{
@@ -1398,7 +1398,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
else if (apply)
{
// modify stack amount of linked auras
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(GetId() + SPELL_LINK_AURA))
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_AURA, GetId()))
{
for (std::vector<int32>::const_iterator itr = spellTriggered->begin(); itr != spellTriggered->end(); ++itr)
if (*itr > 0)

View File

@@ -3205,7 +3205,7 @@ void Spell::DoTriggersOnSpellHit(Unit* unit)
// trigger linked auras remove/apply
/// @todo remove/cleanup this, as this table is not documented and people are doing stupid things with it
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id + SPELL_LINK_HIT))
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_HIT, m_spellInfo->Id))
{
for (std::vector<int32>::const_iterator i = spellTriggered->begin(); i != spellTriggered->end(); ++i)
{
@@ -3746,7 +3746,7 @@ void Spell::_cast(bool skipCheck)
CallScriptAfterCastHandlers();
if (std::vector<int32> const* spell_triggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id))
if (std::vector<int32> const* spell_triggered = sSpellMgr->GetSpellLinked(SPELL_LINK_CAST, m_spellInfo->Id))
{
for (int32 id : *spell_triggered)
{

View File

@@ -625,9 +625,9 @@ bool SpellMgr::IsArenaAllowedEnchancment(uint32 ench_id) const
return false;
}
std::vector<int32> const* SpellMgr::GetSpellLinked(int32 spell_id) const
std::vector<int32> const* SpellMgr::GetSpellLinked(SpellLinkedType type, uint32 spell_id) const
{
return Trinity::Containers::MapGetValuePtr(mSpellLinkedMap, spell_id);
return Trinity::Containers::MapGetValuePtr(mSpellLinkedMap, { type, spell_id });
}
PetLevelupSpellSet const* SpellMgr::GetPetLevelupSpellList(uint32 petFamily) const
@@ -2047,7 +2047,7 @@ void SpellMgr::LoadSpellLinked()
int32 trigger = fields[0].GetInt32();
int32 effect = fields[1].GetInt32();
int32 type = fields[2].GetUInt8();
SpellLinkedType type = SpellLinkedType(fields[2].GetUInt8());
SpellInfo const* spellInfo = GetSpellInfo(abs(trigger), DIFFICULTY_NONE);
if (!spellInfo)
@@ -2057,11 +2057,13 @@ void SpellMgr::LoadSpellLinked()
}
if (effect >= 0)
{
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
{
if (spellEffectInfo.CalcValue() == abs(effect))
TC_LOG_ERROR("sql.sql", "The spell {} Effect: {} listed in `spell_linked_spell` has same bp{} like effect (possible hack).", abs(trigger), abs(effect), uint32(spellEffectInfo.EffectIndex));
}
}
spellInfo = GetSpellInfo(abs(effect), DIFFICULTY_NONE);
if (!spellInfo)
@@ -2070,14 +2072,31 @@ void SpellMgr::LoadSpellLinked()
continue;
}
if (type) //we will find a better way when more types are needed
if (type < SPELL_LINK_CAST || type > SPELL_LINK_REMOVE)
{
if (trigger > 0)
trigger += SPELL_LINKED_MAX_SPELLS * type;
else
trigger -= SPELL_LINKED_MAX_SPELLS * type;
TC_LOG_ERROR("sql.sql", "The spell trigger {}, effect {} listed in `spell_linked_spell` has invalid link type {}, skipped.", trigger, effect, type);
continue;
}
mSpellLinkedMap[trigger].push_back(effect);
if (trigger < 0)
{
if (type != SPELL_LINK_CAST)
TC_LOG_ERROR("sql.sql", "The spell trigger {} listed in `spell_linked_spell` has invalid link type {}, changed to 0.", trigger, type);
trigger = -trigger;
type = SPELL_LINK_REMOVE;
}
if (type != SPELL_LINK_AURA)
{
if (trigger == effect)
{
TC_LOG_ERROR("sql.sql", "The spell trigger {}, effect {} listed in `spell_linked_spell` triggers itself (infinite loop), skipped.", trigger, effect);
continue;
}
}
mSpellLinkedMap[{ type, trigger }].push_back(effect);
++count;
} while (result->NextRow());

View File

@@ -118,14 +118,12 @@ enum SpellFamilyFlag
SPELLFAMILYFLAG_SHAMAN_TOTEM_EFFECTS = 0x04000000 // Seems to be linked to most totems and some totem effects
};
#define SPELL_LINKED_MAX_SPELLS 200000
enum SpellLinkedType
{
SPELL_LINK_CAST = 0, // +: cast; -: remove
SPELL_LINK_HIT = 1 * 200000,
SPELL_LINK_AURA = 2 * 200000, // +: aura; -: immune
SPELL_LINK_REMOVE = 0
SPELL_LINK_HIT = 1,
SPELL_LINK_AURA = 2, // +: aura; -: immune
SPELL_LINK_REMOVE = 3
};
// Spell proc event related declarations (accessed using SpellMgr functions)
@@ -617,7 +615,7 @@ struct PetDefaultSpellsEntry
// < 0 for petspelldata id, > 0 for creature_id
typedef std::map<int32, PetDefaultSpellsEntry> PetDefaultSpellsMap;
typedef std::unordered_map<int32, std::vector<int32>> SpellLinkedMap;
typedef std::unordered_map<std::pair<SpellLinkedType, uint32>, std::vector<int32>> SpellLinkedMap;
bool IsPrimaryProfessionSkill(uint32 skill);
@@ -733,7 +731,7 @@ class TC_GAME_API SpellMgr
SpellEnchantProcEntry const* GetSpellEnchantProcEvent(uint32 enchId) const;
bool IsArenaAllowedEnchancment(uint32 ench_id) const;
std::vector<int32> const* GetSpellLinked(int32 spell_id) const;
std::vector<int32> const* GetSpellLinked(SpellLinkedType type, uint32 spell_id) const;
PetLevelupSpellSet const* GetPetLevelupSpellList(uint32 petFamily) const;
PetDefaultSpellsEntry const* GetPetDefaultSpellsEntry(int32 id) const;