fix(Core/Vehicle): avoid Vehicle-kit use-after-free in TeleportVehicle (#26116)

Co-authored-by: sudlud <[email protected]>
This commit is contained in:
mpfans
2026-09-12 23:09:33 +02:00
committed by GitHub
co-authored by sudlud
parent a20beb0a80
commit d93aa1eb30
+25 -4
View File
@@ -599,12 +599,33 @@ bool Vehicle::IsControllableVehicle() const
void Vehicle::TeleportVehicle(float x, float y, float z, float ang)
{
_me->GetMap()->LoadGrid(x, y);
_me->NearTeleportTo(x, y, z, ang, true);
// Snapshot passenger GUIDs and cache the base BEFORE teleporting.
// Teleporting the base (Player::TeleportTo) may drop the mount/vehicle aura
// on a long hop (>100 yd) and call ExitVehicle() -> Unit::RemoveVehicleKit()
// -> delete m_vehicleKit, freeing THIS Vehicle (and its Seats) mid-call.
// Reading Seats after that is a use-after-free (see upstream PR #26116 review).
Unit* base = _me;
Vehicle* self = this;
std::vector<ObjectGuid> passengers;
passengers.reserve(Seats.size());
for (auto const& seat : Seats)
if (!seat.second.IsEmpty())
passengers.push_back(seat.second.Passenger.Guid);
for (SeatMap::const_iterator itr = Seats.begin(); itr != Seats.end(); ++itr)
if (Unit* passenger = ObjectAccessor::GetUnit(*GetBase(), itr->second.Passenger.Guid))
base->GetMap()->LoadGrid(x, y);
base->NearTeleportTo(x, y, z, ang, true, true); // vehicleTeleport=true: do not dismount base mid-call
// THIS Vehicle may have been deleted by the base teleport above (kit freed).
// If so, bail out - passengers were already ejected by ~Vehicle::Uninstall().
if (base->GetVehicleKit() != self)
return;
for (ObjectGuid const& guid : passengers)
if (Unit* passenger = ObjectAccessor::GetUnit(*base, guid))
{
if (!passenger->IsInWorld())
continue;
if (passenger->IsPlayer())
{
passenger->ToPlayer()->SetMover(passenger);