fix(Core/Movement): Fix use-after-free in WaypointMovementGenerator (#25270)
Co-authored-by: blinkysc <blinkysc@users.noreply.github.com> Co-authored-by: Shauren <shauren.trinity@gmail.com> Co-authored-by: ccrs <ccrs@users.noreply.github.com>
This commit is contained in:
@@ -879,10 +879,10 @@ void MotionMaster::MoveDistract(uint32 timer)
|
|||||||
|
|
||||||
void MotionMaster::Mutate(MovementGenerator* m, MovementSlot slot)
|
void MotionMaster::Mutate(MovementGenerator* m, MovementSlot slot)
|
||||||
{
|
{
|
||||||
|
bool const delayed = (_cleanFlag & MMCF_UPDATE);
|
||||||
|
|
||||||
while (MovementGenerator* curr = Impl[slot])
|
while (MovementGenerator* curr = Impl[slot])
|
||||||
{
|
{
|
||||||
bool delayed = (_top == slot && (_cleanFlag & MMCF_UPDATE));
|
|
||||||
|
|
||||||
// clear slot AND decrease top immediately to avoid crashes when referencing null top in DirectDelete
|
// clear slot AND decrease top immediately to avoid crashes when referencing null top in DirectDelete
|
||||||
Impl[slot] = nullptr;
|
Impl[slot] = nullptr;
|
||||||
while (!empty() && !top())
|
while (!empty() && !top())
|
||||||
|
|||||||
@@ -157,27 +157,31 @@ void WaypointMovementGenerator<Creature>::ProcessWaypointArrival(Creature* creat
|
|||||||
creature->GetMap()->ScriptsStart(sWaypointScripts, waypoint.EventId, creature, nullptr);
|
creature->GetMap()->ScriptsStart(sWaypointScripts, waypoint.EventId, creature, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
creature->UpdateWaypointID(waypoint.Id);
|
// scripts can invalidate current path, store what we need
|
||||||
creature->UpdateCurrentWaypointInfo(waypoint.Id, i_path->Id);
|
uint32 const waypointId = waypoint.Id;
|
||||||
|
uint32 const pathId = i_path->Id;
|
||||||
|
|
||||||
|
creature->UpdateWaypointID(waypointId);
|
||||||
|
creature->UpdateCurrentWaypointInfo(waypointId, pathId);
|
||||||
|
|
||||||
// Inform AI
|
// Inform AI
|
||||||
if (CreatureAI* AI = creature->AI())
|
if (CreatureAI* AI = creature->AI())
|
||||||
{
|
{
|
||||||
AI->MovementInform(WAYPOINT_MOTION_TYPE, waypoint.Id);
|
AI->MovementInform(WAYPOINT_MOTION_TYPE, waypointId);
|
||||||
AI->WaypointReached(waypoint.Id, i_path->Id);
|
AI->WaypointReached(waypointId, pathId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Unit* owner = creature->GetCharmerOrOwner())
|
if (Unit* owner = creature->GetCharmerOrOwner())
|
||||||
{
|
{
|
||||||
if (UnitAI* AI = owner->GetAI())
|
if (UnitAI* AI = owner->GetAI())
|
||||||
AI->SummonMovementInform(creature, WAYPOINT_MOTION_TYPE, waypoint.Id);
|
AI->SummonMovementInform(creature, WAYPOINT_MOTION_TYPE, waypointId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (TempSummon* tempSummon = creature->ToTempSummon())
|
if (TempSummon* tempSummon = creature->ToTempSummon())
|
||||||
if (Unit* owner2 = tempSummon->GetSummonerUnit())
|
if (Unit* owner2 = tempSummon->GetSummonerUnit())
|
||||||
if (UnitAI* AI = owner2->GetAI())
|
if (UnitAI* AI = owner2->GetAI())
|
||||||
AI->SummonMovementInform(creature, WAYPOINT_MOTION_TYPE, waypoint.Id);
|
AI->SummonMovementInform(creature, WAYPOINT_MOTION_TYPE, waypointId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path end notifications fire after WaypointReached so that m_path_id
|
// Path end notifications fire after WaypointReached so that m_path_id
|
||||||
@@ -187,11 +191,11 @@ void WaypointMovementGenerator<Creature>::ProcessWaypointArrival(Creature* creat
|
|||||||
creature->UpdateCurrentWaypointInfo(0, 0);
|
creature->UpdateCurrentWaypointInfo(0, 0);
|
||||||
|
|
||||||
if (CreatureAI* AI = creature->AI())
|
if (CreatureAI* AI = creature->AI())
|
||||||
AI->PathEndReached(i_path->Id);
|
AI->PathEndReached(pathId);
|
||||||
|
|
||||||
// Re-fetch AI — PathEndReached may have despawned the creature or swapped its AI
|
// Re-fetch AI — PathEndReached may have despawned the creature or swapped its AI
|
||||||
if (CreatureAI* AI = creature->AI())
|
if (CreatureAI* AI = creature->AI())
|
||||||
AI->WaypointPathEnded(waypoint.Id, i_path->Id);
|
AI->WaypointPathEnded(waypointId, pathId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All hooks called and infos updated. Time to increment the waypoint node id
|
// All hooks called and infos updated. Time to increment the waypoint node id
|
||||||
@@ -385,8 +389,15 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 di
|
|||||||
WaypointNode const& passedWp = i_path->Nodes.at(i_currentNode);
|
WaypointNode const& passedWp = i_path->Nodes.at(i_currentNode);
|
||||||
|
|
||||||
UpdateHomePosition(creature, passedWp);
|
UpdateHomePosition(creature, passedWp);
|
||||||
creature->UpdateWaypointID(passedWp.Id);
|
|
||||||
creature->UpdateCurrentWaypointInfo(passedWp.Id, i_path->Id);
|
// Save data before AI callbacks — they can invalidate the reference
|
||||||
|
uint32 const wpId = passedWp.Id;
|
||||||
|
uint32 const wpPathId = i_path->Id;
|
||||||
|
uint32 const wpDelay = passedWp.Delay;
|
||||||
|
std::optional<float> const wpOrientation = passedWp.Orientation;
|
||||||
|
|
||||||
|
creature->UpdateWaypointID(wpId);
|
||||||
|
creature->UpdateCurrentWaypointInfo(wpId, wpPathId);
|
||||||
|
|
||||||
if (passedWp.EventId && urand(0, 99) < passedWp.EventChance)
|
if (passedWp.EventId && urand(0, 99) < passedWp.EventChance)
|
||||||
{
|
{
|
||||||
@@ -396,23 +407,24 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 di
|
|||||||
|
|
||||||
if (CreatureAI* AI = creature->AI())
|
if (CreatureAI* AI = creature->AI())
|
||||||
{
|
{
|
||||||
AI->MovementInform(WAYPOINT_MOTION_TYPE, passedWp.Id);
|
AI->MovementInform(WAYPOINT_MOTION_TYPE, wpId);
|
||||||
AI->WaypointReached(passedWp.Id, i_path->Id);
|
AI->WaypointReached(wpId, wpPathId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance node
|
// Advance node
|
||||||
i_currentNode = (i_currentNode + 1) % i_path->Nodes.size();
|
if (i_path && !i_path->Nodes.empty())
|
||||||
|
i_currentNode = (i_currentNode + 1) % i_path->Nodes.size();
|
||||||
|
|
||||||
// If this waypoint has a delay, stop the spline and pause
|
// If this waypoint has a delay, stop the spline and pause
|
||||||
if (passedWp.Delay > 0)
|
if (wpDelay > 0)
|
||||||
{
|
{
|
||||||
creature->StopMoving();
|
creature->StopMoving();
|
||||||
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
|
creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
|
||||||
_waypointDelay = passedWp.Delay;
|
_waypointDelay = wpDelay;
|
||||||
_waypointReached = true;
|
_waypointReached = true;
|
||||||
_smoothSplineLaunched = false;
|
_smoothSplineLaunched = false;
|
||||||
if (passedWp.Orientation.has_value())
|
if (wpOrientation.has_value())
|
||||||
creature->SetFacingTo(*passedWp.Orientation);
|
creature->SetFacingTo(*wpOrientation);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -423,15 +435,17 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 di
|
|||||||
if (!_repeating)
|
if (!_repeating)
|
||||||
{
|
{
|
||||||
// Path ended
|
// Path ended
|
||||||
|
uint32 const endWpId = i_path->Nodes.at(i_currentNode).Id;
|
||||||
|
uint32 const endPathId = i_path->Id;
|
||||||
_done = true;
|
_done = true;
|
||||||
_smoothSplineLaunched = false;
|
_smoothSplineLaunched = false;
|
||||||
creature->UpdateCurrentWaypointInfo(0, 0);
|
creature->UpdateCurrentWaypointInfo(0, 0);
|
||||||
if (CreatureAI* AI = creature->AI())
|
if (CreatureAI* AI = creature->AI())
|
||||||
AI->PathEndReached(i_path->Id);
|
AI->PathEndReached(endPathId);
|
||||||
|
|
||||||
// Re-fetch AI — PathEndReached may have despawned the creature or swapped its AI
|
// Re-fetch AI — PathEndReached may have despawned the creature or swapped its AI
|
||||||
if (CreatureAI* AI = creature->AI())
|
if (CreatureAI* AI = creature->AI())
|
||||||
AI->WaypointPathEnded(i_path->Nodes.at(i_currentNode).Id, i_path->Id);
|
AI->WaypointPathEnded(endWpId, endPathId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user