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 depot memory leak #4879

Merged
merged 1 commit into from
Dec 22, 2024
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
9 changes: 9 additions & 0 deletions src/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,15 @@ void Container::postRemoveNotification(Thing* thing, const Cylinder* newParent,
}
}

void Container::internalRemoveThing(Thing* thing)
{
auto cit = std::find(itemlist.begin(), itemlist.end(), thing);
if (cit == itemlist.end()) {
return;
}
itemlist.erase(cit);
}

void Container::internalAddThing(Thing* thing) { internalAddThing(0, thing); }

void Container::internalAddThing(uint32_t, Thing* thing)
Expand Down
1 change: 1 addition & 0 deletions src/container.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class Container : public Item, public Cylinder
void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index,
cylinderlink_t link = LINK_OWNER) override;

void internalRemoveThing(Thing* thing) override final;
void internalAddThing(Thing* thing) override final;
void internalAddThing(uint32_t index, Thing* thing) override final;
void startDecaying() override final;
Expand Down
5 changes: 5 additions & 0 deletions src/cylinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ std::map<uint32_t, uint32_t>& Cylinder::getAllItemTypeCount(std::map<uint32_t, u

Thing* Cylinder::getThing(size_t) const { return nullptr; }

void Cylinder::internalRemoveThing(Thing*)
{
//
}

void Cylinder::internalAddThing(Thing*)
{
//
Expand Down
6 changes: 6 additions & 0 deletions src/cylinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ class Cylinder : virtual public Thing
*/
virtual std::map<uint32_t, uint32_t>& getAllItemTypeCount(std::map<uint32_t, uint32_t>& countMap) const;

/**
* Removes an object from the cylinder without sending to the client(s)
* \param thing is the object to add
*/
virtual void internalRemoveThing(Thing* thing);

/**
* Adds an object to the cylinder without sending to the client(s)
* \param thing is the object to add
Expand Down
3 changes: 3 additions & 0 deletions src/depotchest.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

#include "container.h"

class DepotChest;
using DepotChest_ptr = std::shared_ptr<DepotChest>;

class DepotChest final : public Container
{
public:
Expand Down
2 changes: 1 addition & 1 deletion src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5561,7 +5561,7 @@ std::vector<Item*> Game::getMarketItemList(uint16_t wareId, uint16_t sufficientC

for (const auto& chest : player.depotChests) {
if (!chest.second->empty()) {
containers.push_front(chest.second);
containers.push_front(chest.second.get());
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/iologindata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,8 +410,7 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)

int32_t pid = pair.second;
if (pid >= 0 && pid < 100) {
DepotChest* depotChest = player->getDepotChest(pid, true);
if (depotChest) {
if (const auto& depotChest = player->getDepotChest(pid, true)) {
depotChest->internalAddThing(item);
}
} else {
Expand Down
6 changes: 3 additions & 3 deletions src/luascript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9087,10 +9087,10 @@ int LuaScriptInterface::luaPlayerGetDepotChest(lua_State* L)

uint32_t depotId = tfs::lua::getNumber<uint32_t>(L, 2);
bool autoCreate = tfs::lua::getBoolean(L, 3, false);
DepotChest* depotChest = player->getDepotChest(depotId, autoCreate);
const auto& depotChest = player->getDepotChest(depotId, autoCreate);
if (depotChest) {
tfs::lua::pushUserdata<Item>(L, depotChest);
tfs::lua::setItemMetatable(L, -1, depotChest);
pushSharedPtr(L, depotChest);
tfs::lua::setItemMetatable(L, -1, depotChest.get());
} else {
tfs::lua::pushBoolean(L, false);
}
Expand Down
23 changes: 16 additions & 7 deletions src/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ Player::~Player()
}
}

for (const auto& [_, depot] : depotChests) {
if (Cylinder* parent = depot->getRealParent()) {
// remove chest from depot locker, because of possible double free when shared_ptr decides to free up the
// resource
parent->internalRemoveThing(depot.get());
}
}

if (depotLocker) {
depotLocker->removeInbox(inbox);
}
Expand Down Expand Up @@ -814,7 +822,7 @@ bool Player::isNearDepotBox() const
return false;
}

DepotChest* Player::getDepotChest(uint32_t depotId, bool autoCreate)
DepotChest_ptr Player::getDepotChest(uint32_t depotId, bool autoCreate)
{
auto it = depotChests.find(depotId);
if (it != depotChests.end()) {
Expand All @@ -830,9 +838,10 @@ DepotChest* Player::getDepotChest(uint32_t depotId, bool autoCreate)
return nullptr;
}

it = depotChests.emplace(depotId, new DepotChest(depotItemId)).first;
it->second->setMaxDepotItems(getMaxDepotItems());
return it->second;
const DepotChest_ptr& depotChest =
depotChests.emplace(depotId, std::make_shared<DepotChest>(depotItemId)).first->second;
depotChest->setMaxDepotItems(getMaxDepotItems());
return depotChest;
}

DepotLocker& Player::getDepotLocker()
Expand All @@ -845,8 +854,8 @@ DepotLocker& Player::getDepotLocker()
DepotChest* depotChest = new DepotChest(ITEM_DEPOT, false);
// adding in reverse to align them from first to last
for (int16_t depotId = depotChest->capacity(); depotId >= 0; --depotId) {
if (DepotChest* box = getDepotChest(depotId, true)) {
depotChest->internalAddThing(box);
if (const auto& box = getDepotChest(depotId, true)) {
depotChest->internalAddThing(box.get());
}
}

Expand Down Expand Up @@ -3205,7 +3214,7 @@ void Player::postRemoveNotification(Thing* thing, const Cylinder* newParent, int
bool isOwner = false;

for (const auto& it : depotChests) {
if (it.second == depotChest) {
if (it.second.get() == depotChest) {
isOwner = true;
onSendContainer(container);
}
Expand Down
6 changes: 3 additions & 3 deletions src/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "creature.h"
#include "cylinder.h"
#include "depotchest.h"
#include "depotlocker.h"
#include "enums.h"
#include "groups.h"
Expand All @@ -14,7 +15,6 @@
#include "town.h"
#include "vocation.h"

class DepotChest;
class House;
struct Mount;
class NetworkMessage;
Expand Down Expand Up @@ -356,7 +356,7 @@ class Player final : public Creature, public Cylinder
void addConditionSuppressions(uint32_t conditions);
void removeConditionSuppressions(uint32_t conditions);

DepotChest* getDepotChest(uint32_t depotId, bool autoCreate);
DepotChest_ptr getDepotChest(uint32_t depotId, bool autoCreate);
DepotLocker& getDepotLocker();
void onReceiveMail() const;
bool isNearDepotBox() const;
Expand Down Expand Up @@ -1167,7 +1167,7 @@ class Player final : public Creature, public Cylinder
std::unordered_set<uint32_t> VIPList;

std::map<uint8_t, OpenContainer> openContainers;
std::map<uint32_t, DepotChest*> depotChests;
std::map<uint32_t, DepotChest_ptr> depotChests;

std::map<uint16_t, uint8_t> outfits;
std::unordered_set<uint16_t> mounts;
Expand Down
2 changes: 1 addition & 1 deletion src/protocolgame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2104,7 +2104,7 @@ void ProtocolGame::sendMarketEnter()

for (const auto& chest : player->depotChests) {
if (!chest.second->empty()) {
containerList.push_front(chest.second);
containerList.push_front(chest.second.get());
}
}

Expand Down
Loading