Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: possible crash related to unsafe "getTile" #1095

Merged
merged 4 commits into from
May 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/creatures/combat/combat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ ReturnValue Combat::canDoCombat(Creature* attacker, Creature* target) {
return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
}

const Tile* targetPlayerTile = targetPlayer->getTile();

if (const Player* attackerPlayer = attacker->getPlayer()) {
if (attackerPlayer->hasFlag(PlayerFlags_t::CannotAttackPlayer)) {
return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
Expand All @@ -286,10 +288,10 @@ ReturnValue Combat::canDoCombat(Creature* attacker, Creature* target) {
}

// nopvp-zone
if (const Tile* targetPlayerTile = targetPlayer->getTile();
targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE)) {
auto attackerTile = attackerPlayer->getTile();
if (targetPlayerTile && targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE)) {
return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
} else if (attackerPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE) && !targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE | TILESTATE_PROTECTIONZONE)) {
} else if (attackerTile && attackerTile->hasFlag(TILESTATE_NOPVPZONE) && targetPlayerTile && !targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE | TILESTATE_PROTECTIONZONE)) {
return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
}

Expand All @@ -304,7 +306,7 @@ ReturnValue Combat::canDoCombat(Creature* attacker, Creature* target) {
return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
}

if (targetPlayer->getTile()->hasFlag(TILESTATE_NOPVPZONE)) {
if (targetPlayerTile && targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE)) {
return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
}

Expand Down Expand Up @@ -1651,8 +1653,8 @@ void MagicField::onStepInField(Creature &creature) {
auto ownerId = getAttribute<uint32_t>(ItemAttribute_t::OWNER);
if (ownerId) {
bool harmfulField = true;

if (g_game().getWorldType() == WORLD_TYPE_NO_PVP || getTile()->hasFlag(TILESTATE_NOPVPZONE)) {
auto itemTile = getTile();
if (g_game().getWorldType() == WORLD_TYPE_NO_PVP || itemTile && itemTile->hasFlag(TILESTATE_NOPVPZONE)) {
Creature* owner = g_game().getCreatureByID(ownerId);
if (owner) {
if (owner->getPlayer() || (owner->isSummon() && owner->getMaster()->getPlayer())) {
Expand Down
21 changes: 14 additions & 7 deletions src/creatures/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,18 +419,23 @@ void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) cons

const Position &pos = creature->getPosition();
const Monster* monster = creature->getMonster();
bool protectionZoneCheck = this->getTile()->hasFlag(TILESTATE_PROTECTIONZONE);
bool protectionZoneCheck = tile ? tile->hasFlag(TILESTATE_PROTECTIONZONE) : false;
// Check if any of our summons is out of range (+/- 0 floors or 15 tiles away)
bool checkSummonDist = Position::getDistanceZ(newPos, pos) > 0 || (std::max<int32_t>(Position::getDistanceX(newPos, pos), Position::getDistanceY(newPos, pos)) > 15);
// Check if any of our summons is out of range (+/- 2 floors or 30 tiles away)
bool checkRemoveDist = Position::getDistanceZ(newPos, pos) > 2 || (std::max<int32_t>(Position::getDistanceX(newPos, pos), Position::getDistanceY(newPos, pos)) > 30);

if (monster && monster->isFamiliar() && checkSummonDist || teleportSummon && !protectionZoneCheck && checkSummonDist) {
if (Tile* masterTile = creature->getMaster()->getTile()) {
auto creatureMaster = creature->getMaster();
if (!creatureMaster) {
continue;
}

if (Tile* masterTile = creatureMaster->getTile()) {
if (masterTile->hasFlag(TILESTATE_TELEPORT)) {
SPDLOG_WARN("[{}] cannot teleport summon, position has teleport. {}", __FUNCTION__, creature->getMaster()->getPosition().toString());
SPDLOG_WARN("[{}] cannot teleport summon, position has teleport. {}", __FUNCTION__, creatureMaster->getPosition().toString());
} else {
g_game().internalTeleport(creature, creature->getMaster()->getPosition(), true);
g_game().internalTeleport(creature, creatureMaster->getPosition(), true);
continue;
}
}
Expand Down Expand Up @@ -880,7 +885,8 @@ BlockType_t Creature::blockHit(Creature* attacker, CombatType_t combatType, int3

bool Creature::setAttackedCreature(Creature* creature) {
if (creature) {
if (this->getMonster() && this->getMonster()->isFamiliar() && this->getTile() && this->getTile()->hasFlag(TILESTATE_PROTECTIONZONE)) {
auto monster = getMonster();
if (monster && monster->isFamiliar() && tile && tile->hasFlag(TILESTATE_PROTECTIONZONE)) {
return false;
}

Expand Down Expand Up @@ -962,7 +968,8 @@ void Creature::goToFollowCreature() {
}

bool Creature::canFollowMaster() const {
return !master->getTile()->hasFlag(TILESTATE_PROTECTIONZONE) && (canSeeInvisibility() || !master->isInvisible());
auto tile = master->getTile();
return tile && !tile->hasFlag(TILESTATE_PROTECTIONZONE) && (canSeeInvisibility() || !master->isInvisible());
}

bool Creature::setFollowCreature(Creature* creature) {
Expand Down Expand Up @@ -1056,7 +1063,7 @@ void Creature::onEndCondition(ConditionType_t) {
}

void Creature::onTickCondition(ConditionType_t type, bool &bRemove) {
const MagicField* field = getTile()->getFieldItem();
const MagicField* field = tile ? tile->getFieldItem() : nullptr;
if (!field) {
return;
}
Expand Down
6 changes: 5 additions & 1 deletion src/creatures/creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,11 @@ class Creature : virtual public Thing {
}
bool isInvisible() const;
ZoneType_t getZone() const {
return getTile()->getZone();
if (getTile()) {
return tile->getZone();
}

return ZONE_NORMAL;
}

// walk functions
Expand Down
13 changes: 9 additions & 4 deletions src/creatures/players/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1928,8 +1928,8 @@ void Player::onThink(uint32_t interval) {

// Momentum (cooldown resets)
triggerMomentum();

if (!getTile()->hasFlag(TILESTATE_NOLOGOUT) && !isAccessPlayer() && !isExerciseTraining()) {
auto playerTile = getTile();
if (playerTile && !playerTile->hasFlag(TILESTATE_NOLOGOUT) && !isAccessPlayer() && !isExerciseTraining()) {
idleTime += interval;
const int32_t kickAfterMinutes = g_configManager().getNumber(KICK_AFTER_MINUTES);
if (idleTime > (kickAfterMinutes * 60000) + 60000) {
Expand Down Expand Up @@ -4525,11 +4525,16 @@ bool Player::canLogout() {
return false;
}

if (getTile()->hasFlag(TILESTATE_NOLOGOUT)) {
auto tile = getTile();
if (!tile) {
return false;
}

if (tile->hasFlag(TILESTATE_NOLOGOUT)) {
return false;
}

if (getTile()->hasFlag(TILESTATE_PROTECTIONZONE)) {
if (tile->hasFlag(TILESTATE_PROTECTIONZONE)) {
return true;
}

Expand Down
30 changes: 26 additions & 4 deletions src/creatures/players/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -937,8 +937,17 @@ class Player final : public Creature, public Cylinder {
}
}
void sendCreatureAppear(const Creature* creature, const Position &pos, bool isLogin) {
if (!creature) {
return;
}

auto tile = creature->getTile();
if (!tile) {
return;
}

if (client) {
client->sendAddCreature(creature, pos, creature->getTile()->getStackposOfCreature(this, creature), isLogin);
client->sendAddCreature(creature, pos, tile->getStackposOfCreature(this, creature), isLogin);
}
}
void sendCreatureMove(const Creature* creature, const Position &newPos, int32_t newStackPos, const Position &oldPos, int32_t oldStackPos, bool teleport) {
Expand All @@ -947,8 +956,17 @@ class Player final : public Creature, public Cylinder {
}
}
void sendCreatureTurn(const Creature* creature) {
if (!creature) {
return;
}

auto tile = creature->getTile();
if (!tile) {
return;
}

if (client && canSeeCreature(creature)) {
int32_t stackpos = creature->getTile()->getStackposOfCreature(this, creature);
int32_t stackpos = tile->getStackposOfCreature(this, creature);
if (stackpos != -1) {
client->sendCreatureTurn(creature, stackpos);
}
Expand Down Expand Up @@ -980,7 +998,7 @@ class Player final : public Creature, public Cylinder {
}
}
void sendCreatureChangeVisible(const Creature* creature, bool visible) {
if (!client) {
if (!client || !creature) {
return;
}

Expand All @@ -994,7 +1012,11 @@ class Player final : public Creature, public Cylinder {
} else if (canSeeInvisibility()) {
client->sendCreatureOutfit(creature, creature->getCurrentOutfit());
} else {
int32_t stackpos = creature->getTile()->getStackposOfCreature(this, creature);
auto tile = creature->getTile();
if (!tile) {
return;
}
int32_t stackpos = tile->getStackposOfCreature(this, creature);
if (stackpos == -1) {
return;
}
Expand Down
10 changes: 8 additions & 2 deletions src/game/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,10 @@ void Game::playerMoveCreature(Player* player, Creature* movingCreature, const Po
}

ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction, uint32_t flags /*= 0*/) {
if (!creature) {
return RETURNVALUE_NOTPOSSIBLE;
}

creature->setLastPosition(creature->getPosition());
const Position &currentPos = creature->getPosition();
Position destPos = getNextPosition(direction, currentPos);
Expand All @@ -1103,7 +1107,8 @@ ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction,
bool diagonalMovement = (direction & DIRECTION_DIAGONAL_MASK) != 0;
if (player && !diagonalMovement) {
// try go up
if (currentPos.z != 8 && creature->getTile()->hasHeight(3)) {
auto tile = creature->getTile();
if (currentPos.z != 8 && tile && tile->hasHeight(3)) {
Tile* tmpTile = map.getTile(currentPos.x, currentPos.y, currentPos.getZ() - 1);
if (tmpTile == nullptr || (tmpTile->getGround() == nullptr && !tmpTile->hasFlag(TILESTATE_BLOCKSOLID))) {
tmpTile = map.getTile(destPos.x, destPos.y, destPos.getZ() - 1);
Expand Down Expand Up @@ -1290,7 +1295,8 @@ void Game::playerMoveItem(Player* player, const Position &fromPos, uint16_t item
}

const Position &playerPos = player->getPosition();
const Position &mapFromPos = fromCylinder->getTile()->getPosition();
auto cylinderTile = fromCylinder->getTile();
const Position &mapFromPos = cylinderTile ? cylinderTile->getPosition() : item->getPosition();
if (playerPos.z != mapFromPos.z) {
player->sendCancelMessage(playerPos.z > mapFromPos.z ? RETURNVALUE_FIRSTGOUPSTAIRS : RETURNVALUE_FIRSTGODOWNSTAIRS);
return;
Expand Down
30 changes: 23 additions & 7 deletions src/server/network/protocol/protocolgame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,13 +452,14 @@ void ProtocolGame::logout(bool displayEffect, bool forced) {
}

bool removePlayer = !player->isRemoved() && !forced;
auto tile = player->getTile();
if (removePlayer && !player->isAccessPlayer()) {
if (player->getTile()->hasFlag(TILESTATE_NOLOGOUT)) {
if (tile && tile->hasFlag(TILESTATE_NOLOGOUT)) {
player->sendCancelMessage(RETURNVALUE_YOUCANNOTLOGOUTHERE);
return;
}

if (!player->getTile()->hasFlag(TILESTATE_PROTECTIONZONE) && player->hasCondition(CONDITION_INFIGHT)) {
if (tile && !tile->hasFlag(TILESTATE_PROTECTIONZONE) && player->hasCondition(CONDITION_INFIGHT)) {
player->sendCancelMessage(RETURNVALUE_YOUMAYNOTLOGOUTDURINGAFIGHT);
return;
}
Expand Down Expand Up @@ -2931,13 +2932,18 @@ void ProtocolGame::sendCreatureShield(const Creature* creature) {
}

void ProtocolGame::sendCreatureEmblem(const Creature* creature) {
if (!canSee(creature) || oldProtocol) {
if (!creature || !canSee(creature) || oldProtocol) {
return;
}

auto tile = creature->getTile();
if (!tile) {
return;
}

// Remove creature from client and re-add to update
Position pos = creature->getPosition();
int32_t stackpos = creature->getTile()->getClientIndexOfCreature(player, creature);
int32_t stackpos = tile->getClientIndexOfCreature(player, creature);
sendRemoveTileThing(pos, stackpos);
NetworkMessage msg;
msg.addByte(0x6A);
Expand Down Expand Up @@ -7239,10 +7245,15 @@ void ProtocolGame::sendItemsPrice() {
}

void ProtocolGame::reloadCreature(const Creature* creature) {
if (!canSee(creature))
if (!creature || !canSee(creature))
return;

auto tile = creature->getTile();
if (!tile) {
return;
}

uint32_t stackpos = creature->getTile()->getClientIndexOfCreature(player, creature);
uint32_t stackpos = tile->getClientIndexOfCreature(player, creature);

if (stackpos >= 10)
return;
Expand Down Expand Up @@ -7469,10 +7480,15 @@ void ProtocolGame::sendUpdateCreature(const Creature* creature) {
return;
}

auto tile = creature->getTile();
if (!tile) {
return;
}

if (!canSee(creature))
return;

int32_t stackPos = creature->getTile()->getClientIndexOfCreature(player, creature);
int32_t stackPos = tile->getClientIndexOfCreature(player, creature);
if (stackPos == -1 || stackPos >= 10) {
return;
}
Expand Down