From d024f0a39665a945eeb1fef62d17b2231b21020d Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 28 Feb 2018 23:53:20 +1100 Subject: [PATCH] fix eobj out of bounds allocation client crash --- src/common/Common.h | 1 + .../Network/PacketDef/Zone/ServerZoneDef.h | 2 +- .../sapphire_zone/Actor/EventObject.cpp | 4 ++- src/servers/sapphire_zone/Actor/Player.cpp | 32 +++++++++++++++++-- src/servers/sapphire_zone/Actor/Player.h | 9 +++++- .../sapphire_zone/Zone/InstanceContent.cpp | 3 ++ 6 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index 6d5b204d..05517df7 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -16,6 +16,7 @@ namespace Common { // 99 is the last spawn id that seems to spawn any actor const uint8_t MAX_DISPLAYED_ACTORS = 99; + const uint8_t MAX_DISPLAYED_EOBJS = 40; const int32_t INVALID_GAME_OBJECT_ID = 0xE0000000; diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 985af408..8684985d 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1316,7 +1316,7 @@ struct FFXIVIpcMSQTrackerComplete : FFXIVIpcBasePacket struct FFXIVIpcObjectSpawn : FFXIVIpcBasePacket { - uint8_t count; + uint8_t spawnIndex; uint8_t objKind; uint8_t state; uint8_t unknown3; diff --git a/src/servers/sapphire_zone/Actor/EventObject.cpp b/src/servers/sapphire_zone/Actor/EventObject.cpp index e624c124..4592fad5 100644 --- a/src/servers/sapphire_zone/Actor/EventObject.cpp +++ b/src/servers/sapphire_zone/Actor/EventObject.cpp @@ -100,7 +100,7 @@ void Core::Entity::EventObject::spawn( Core::Entity::PlayerPtr pTarget ) { g_log.debug( "Spawning EObj: id:" + std::to_string( getId() ) + " name:" + getName() ); ZoneChannelPacket< FFXIVIpcObjectSpawn > eobjStatePacket( getId(), pTarget->getId() ); - eobjStatePacket.data().count = pTarget->getNextObjCount(); + eobjStatePacket.data().spawnIndex = pTarget->getNextObjSpawnIndexForActorId( getId( )); eobjStatePacket.data().objKind = getObjKind(); eobjStatePacket.data().state = getState(); eobjStatePacket.data().objId = getObjectId(); @@ -115,6 +115,8 @@ void Core::Entity::EventObject::spawn( Core::Entity::PlayerPtr pTarget ) void Core::Entity::EventObject::despawn( Core::Entity::PlayerPtr pTarget ) { g_log.debug( "despawn eobj: " + std::to_string( getId() ) ); + + pTarget->freeObjSpawnIndexForActorId( getId( )); } const std::string& Core::Entity::EventObject::getName() const diff --git a/src/servers/sapphire_zone/Actor/Player.cpp b/src/servers/sapphire_zone/Actor/Player.cpp index 65ab2fe5..f3f3b68a 100644 --- a/src/servers/sapphire_zone/Actor/Player.cpp +++ b/src/servers/sapphire_zone/Actor/Player.cpp @@ -1659,9 +1659,37 @@ void Core::Entity::Player::teleportQuery( uint16_t aetheryteId ) } } -uint8_t Core::Entity::Player::getNextObjCount() +uint8_t Core::Entity::Player::getNextObjSpawnIndexForActorId( uint32_t actorId ) { - return m_objCount++; + auto nextCount = m_freeObjCounts.front(); + m_freeObjCounts.pop(); + + m_actorIdToObjCountMap[actorId] = nextCount; + + return nextCount; +} + +void Core::Entity::Player::resetObjSpawnIndex() +{ + while( m_freeObjCounts.empty() ) + m_freeObjCounts.pop(); + + for( uint32_t i = 0; i < MAX_DISPLAYED_EOBJS; ++i ) + m_freeObjCounts.push( i ); + + m_actorIdToObjCountMap.clear(); +} + +void Core::Entity::Player::freeObjSpawnIndexForActorId( uint32_t actorId ) +{ + auto it = m_actorIdToObjCountMap.find( actorId ); + if( it == m_actorIdToObjCountMap.end() ) + return; + + auto freeCount = m_actorIdToObjCountMap[actorId]; + m_freeObjCounts.push( freeCount ); + + m_actorIdToObjCountMap.erase( actorId ); } void Core::Entity::Player::setOnEnterEventDone( bool isDone ) diff --git a/src/servers/sapphire_zone/Actor/Player.h b/src/servers/sapphire_zone/Actor/Player.h index 7f362e6a..877de137 100644 --- a/src/servers/sapphire_zone/Actor/Player.h +++ b/src/servers/sapphire_zone/Actor/Player.h @@ -562,7 +562,12 @@ public: void setOnEnterEventDone( bool isDone ); bool isOnEnterEventDone() const; - uint8_t getNextObjCount(); + /*! gets the next available obj count */ + uint8_t getNextObjSpawnIndexForActorId( uint32_t actorId ); + /*! resets the players obj count */ + void resetObjSpawnIndex(); + /*! frees an obj count to be used by another eobj */ + void freeObjSpawnIndexForActorId( uint32_t actorId ); private: uint32_t m_lastWrite; @@ -679,6 +684,8 @@ private: // counter used to index objects spawned for the player uint8_t m_objCount; + std::queue< uint8_t > m_freeObjCounts; + std::map< uint32_t, uint8_t > m_actorIdToObjCountMap; }; } diff --git a/src/servers/sapphire_zone/Zone/InstanceContent.cpp b/src/servers/sapphire_zone/Zone/InstanceContent.cpp index 92910575..58a6fa7c 100644 --- a/src/servers/sapphire_zone/Zone/InstanceContent.cpp +++ b/src/servers/sapphire_zone/Zone/InstanceContent.cpp @@ -221,6 +221,7 @@ void Core::InstanceContent::setVar( uint8_t index, uint8_t value ) } + // todo: genericise this? for( const auto &playerIt : m_playerMap ) { sendDirectorVars( *playerIt.second ); @@ -274,6 +275,8 @@ void Core::InstanceContent::onBeforeEnterTerritory( Core::Entity::Player &player player.setRot( PI ); player.setPos( { 0.f, 0.f, 0.f } ); } + + player.resetObjSpawnIndex( ); } Core::Entity::EventObjectPtr Core::InstanceContent::getEObjByName( const std::string &name )