Skip to content

Commit

Permalink
Fixed crash when creating specific offers with certain amount from in…
Browse files Browse the repository at this point in the history
…box (#453)

Crash reproduced in a very specific scenario, we will not give information to prevent malicious people from abusing the bug on the server of those who did not update with this commit
  • Loading branch information
dudantas authored Jul 26, 2022
1 parent 7e0c03c commit ac2f5b2
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 26 deletions.
57 changes: 32 additions & 25 deletions src/game/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7619,7 +7619,8 @@ void Game::playerCreateMarketOffer(uint32_t playerId, uint8_t type, uint16_t ite
}

DepotLocker* depotLocker = player->getDepotLocker(player->getLastDepotId());
if (!depotLocker) {
if (depotLocker == nullptr) {
SPDLOG_ERROR("[Game::playerCreateMarketOffer] - Sell depot chest is nullptr");
return;
}

Expand All @@ -7638,8 +7639,9 @@ void Game::playerCreateMarketOffer(uint32_t playerId, uint8_t type, uint16_t ite
uint16_t stashminus = player->getStashItemCount(it.wareId);
amount = (amount - (amount > stashminus ? stashminus : amount));

std::forward_list<Item *> itemList = getMarketItemList(it.wareId, amount, depotLocker);
if (itemList.empty() && amount > 0) {
std::vector<Item*> itemVector = getMarketItemList(it.wareId, amount, depotLocker);
if (itemVector.empty() && amount > 0) {
SPDLOG_ERROR("[Game::playerCreateMarketOffer] - Sell item list is empty");
return;
}

Expand All @@ -7648,7 +7650,7 @@ void Game::playerCreateMarketOffer(uint32_t playerId, uint8_t type, uint16_t ite
}

uint16_t tmpAmount = amount;
for (Item *item : itemList) {
for (Item *item : itemVector) {
if (!it.stackable) {
internalRemoveItem(item);
continue;
Expand Down Expand Up @@ -7812,7 +7814,8 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16
// so the market action is 'buy' as who created the offer is buying.
if (offer.type == MARKETACTION_BUY) {
DepotLocker* depotLocker = player->getDepotLocker(player->getLastDepotId());
if (!depotLocker) {
if (depotLocker == nullptr) {
SPDLOG_ERROR("[Game::playerCreateMarketOffer] - Buy depot chest is nullptr");
return;
}

Expand Down Expand Up @@ -7856,14 +7859,15 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16
}

if (removeAmount > 0) {
std::forward_list<Item*> itemList = getMarketItemList(it.wareId, removeAmount, depotLocker);
if (itemList.empty() && removeAmount > 0) {
std::vector<Item*> itemVector = getMarketItemList(it.wareId, amount, depotLocker);
if (itemVector.empty()) {
SPDLOG_ERROR("[Game::playerCreateMarketOffer] - Buy item list is empty");
return;
}

if (it.stackable) {
uint16_t tmpAmount = removeAmount;
for (Item* item : itemList) {
for (Item* item : itemVector) {
if (!item) {
continue;
}
Expand All @@ -7876,7 +7880,7 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16
}
}
} else {
for (Item* item : itemList) {
for (Item* item : itemVector) {
if (!item) {
continue;
}
Expand Down Expand Up @@ -7931,7 +7935,6 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16
delete buyerPlayer;
}
} else if (offer.type == MARKETACTION_SELL) {

Player *sellerPlayer = getPlayerByGUID(offer.playerId);
if (!sellerPlayer) {
sellerPlayer = new Player(nullptr);
Expand Down Expand Up @@ -8468,20 +8471,22 @@ void Game::parsePlayerExtendedOpcode(uint32_t playerId, uint8_t opcode, const st
}
}

std::forward_list<Item*> Game::getMarketItemList(uint16_t wareId, uint16_t sufficientCount, DepotLocker* depotLocker)
std::vector<Item*> Game::getMarketItemList(uint16_t wareId, uint16_t sufficientCount, DepotLocker* depotLocker)
{
std::forward_list<Item*> itemList;
uint16_t count = 0;
std::vector<Item*> itemVector;
itemVector.reserve(std::max<size_t>(32, depotLocker->size()));

std::list<Container*> containers {depotLocker};
do {
Container* container = containers.front();
containers.pop_front();
std::vector<Container*> containers{ depotLocker };
containers.reserve(32);

uint16_t count = 0;
size_t i = 0;
do {
Container* container = containers[i];
for (Item* item : container->getItemList()) {
Container* c = item->getContainer();
if (c && !c->empty()) {
containers.push_back(c);
Container* itemContainer = item->getContainer();
if (itemContainer && !itemContainer->empty()) {
containers.push_back(itemContainer);
continue;
}

Expand All @@ -8490,23 +8495,25 @@ std::forward_list<Item*> Game::getMarketItemList(uint16_t wareId, uint16_t suffi
continue;
}

if (c && (!itemType.isContainer() || c->capacity() != itemType.maxItems)) {
if (itemContainer && (!itemType.isContainer() || itemContainer->capacity() != itemType.maxItems)) {
continue;
}

if (!item->hasMarketAttributes()) {
continue;
}

itemList.push_front(item);
itemVector.push_back(item);

count += Item::countByType(item, -1);
if (count >= sufficientCount) {
return itemList;
return itemVector;
}
}
} while (!containers.empty());
return std::forward_list<Item*>();
} while (++i < containers.size());

itemVector.clear();
return itemVector;
}

void Game::forceRemoveCondition(uint32_t creatureId, ConditionType_t conditionType, ConditionId_t conditionId)
Expand Down
2 changes: 1 addition & 1 deletion src/game/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ class Game

void parsePlayerExtendedOpcode(uint32_t playerId, uint8_t opcode, const std::string& buffer);

std::forward_list<Item*> getMarketItemList(uint16_t wareId, uint16_t sufficientCount, DepotLocker* depotLocker);
std::vector<Item*> getMarketItemList(uint16_t wareId, uint16_t sufficientCount, DepotLocker* depotLocker);

static void updatePremium(account::Account& account);

Expand Down

0 comments on commit ac2f5b2

Please sign in to comment.