Skip to content

Commit

Permalink
fix(Core/Common): Container fixes use after free (azerothcore#21460)
Browse files Browse the repository at this point in the history
  • Loading branch information
sogladev authored Feb 15, 2025
1 parent 7575288 commit a05833e
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 9 deletions.
24 changes: 17 additions & 7 deletions src/common/Utilities/Containers.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,28 @@ namespace Acore::Containers
}

/*
* Select a random element from a container.
* @brief Selects a random element from a container that matches the given predicate
*
* @param container Source container to select from
* @param predicate Unary predicate to filter elements
* @return Iterator to the randomly selected element, or end iterator if no elements match the predicate
*
* Note: container cannot be empty
*/
template<class C, class Predicate>
inline auto SelectRandomContainerElementIf(C const& container, Predicate&& predicate) -> typename std::add_const<decltype(*std::begin(container))>::type&
inline auto SelectRandomContainerElementIf(C const& container, Predicate&& predicate) -> decltype(std::begin(container))
{
C containerCopy;
std::copy_if(std::begin(container), std::end(container), std::inserter(containerCopy, std::end(containerCopy)), predicate);
auto it = std::begin(containerCopy);
std::advance(it, urand(0, uint32(std::size(containerCopy)) - 1));
return *it;
std::vector<decltype(std::begin(container))> matchingElements;

for (auto it = std::begin(container); it != std::end(container); ++it)
if (predicate(*it))
matchingElements.push_back(it);

if (matchingElements.empty())
return std::end(container);

auto randomIt = matchingElements[urand(0, matchingElements.size() - 1)];
return randomIt;
}

/*
Expand Down
5 changes: 5 additions & 0 deletions src/server/game/Entities/Object/Position.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ struct Position
return !(operator==(a));
}

inline bool operator!=(Position const& a) const
{
return !(operator==(a));
}

operator G3D::Vector3() const
{
return { m_positionX, m_positionY, m_positionZ };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,12 @@ class instance_the_black_morass : public InstanceMapScript
{
if (_availableRiftPositions.size() > 1)
{
spawnPos = Acore::Containers::SelectRandomContainerElementIf(_availableRiftPositions, [&](Position pos) -> bool
auto spawnPosItr = Acore::Containers::SelectRandomContainerElementIf(_availableRiftPositions, [&](Position const& pos) -> bool
{
return pos != lastPosition;
});
if (spawnPosItr != _availableRiftPositions.end())
spawnPos = *spawnPosItr;
}
else
{
Expand Down
5 changes: 4 additions & 1 deletion src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,13 @@ struct boss_laj : public BossAI

ScheduleTimedEvent(30s, [&] {
me->RemoveAurasDueToSpell(_lastTransform.spellId);
_lastTransform = Acore::Containers::SelectRandomContainerElementIf(_transformContainer, [&](LajTransformData data) -> bool
auto lastTransformItr = Acore::Containers::SelectRandomContainerElementIf(_transformContainer, [&](LajTransformData const& data) -> bool
{
return data.spellId != _lastTransform.spellId;
});
if (lastTransformItr == _transformContainer.end())
return;
_lastTransform = *lastTransformItr;
me->SetDisplayId(_lastTransform.modelId);
DoCastSelf(_lastTransform.spellId, true);
}, 35s);
Expand Down

0 comments on commit a05833e

Please sign in to comment.