Skip to content

Commit 8d79ba4

Browse files
authored
Fix depot memory leak (#4879)
1 parent 04f6cab commit 8d79ba4

11 files changed

+49
-17
lines changed

src/container.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,15 @@ void Container::postRemoveNotification(Thing* thing, const Cylinder* newParent,
692692
}
693693
}
694694

695+
void Container::internalRemoveThing(Thing* thing)
696+
{
697+
auto cit = std::find(itemlist.begin(), itemlist.end(), thing);
698+
if (cit == itemlist.end()) {
699+
return;
700+
}
701+
itemlist.erase(cit);
702+
}
703+
695704
void Container::internalAddThing(Thing* thing) { internalAddThing(0, thing); }
696705

697706
void Container::internalAddThing(uint32_t, Thing* thing)

src/container.h

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class Container : public Item, public Cylinder
111111
void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index,
112112
cylinderlink_t link = LINK_OWNER) override;
113113

114+
void internalRemoveThing(Thing* thing) override final;
114115
void internalAddThing(Thing* thing) override final;
115116
void internalAddThing(uint32_t index, Thing* thing) override final;
116117
void startDecaying() override final;

src/cylinder.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ std::map<uint32_t, uint32_t>& Cylinder::getAllItemTypeCount(std::map<uint32_t, u
2222

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

25+
void Cylinder::internalRemoveThing(Thing*)
26+
{
27+
//
28+
}
29+
2530
void Cylinder::internalAddThing(Thing*)
2631
{
2732
//

src/cylinder.h

+6
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,12 @@ class Cylinder : virtual public Thing
174174
*/
175175
virtual std::map<uint32_t, uint32_t>& getAllItemTypeCount(std::map<uint32_t, uint32_t>& countMap) const;
176176

177+
/**
178+
* Removes an object from the cylinder without sending to the client(s)
179+
* \param thing is the object to add
180+
*/
181+
virtual void internalRemoveThing(Thing* thing);
182+
177183
/**
178184
* Adds an object to the cylinder without sending to the client(s)
179185
* \param thing is the object to add

src/depotchest.h

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
#include "container.h"
88

9+
class DepotChest;
10+
using DepotChest_ptr = std::shared_ptr<DepotChest>;
11+
912
class DepotChest final : public Container
1013
{
1114
public:

src/game.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -5565,7 +5565,7 @@ std::vector<Item*> Game::getMarketItemList(uint16_t wareId, uint16_t sufficientC
55655565

55665566
for (const auto& chest : player.depotChests) {
55675567
if (!chest.second->empty()) {
5568-
containers.push_front(chest.second);
5568+
containers.push_front(chest.second.get());
55695569
}
55705570
}
55715571

src/iologindata.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,7 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
410410

411411
int32_t pid = pair.second;
412412
if (pid >= 0 && pid < 100) {
413-
DepotChest* depotChest = player->getDepotChest(pid, true);
414-
if (depotChest) {
413+
if (const auto& depotChest = player->getDepotChest(pid, true)) {
415414
depotChest->internalAddThing(item);
416415
}
417416
} else {

src/luascript.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -9087,10 +9087,10 @@ int LuaScriptInterface::luaPlayerGetDepotChest(lua_State* L)
90879087

90889088
uint32_t depotId = tfs::lua::getNumber<uint32_t>(L, 2);
90899089
bool autoCreate = tfs::lua::getBoolean(L, 3, false);
9090-
DepotChest* depotChest = player->getDepotChest(depotId, autoCreate);
9090+
const auto& depotChest = player->getDepotChest(depotId, autoCreate);
90919091
if (depotChest) {
9092-
tfs::lua::pushUserdata<Item>(L, depotChest);
9093-
tfs::lua::setItemMetatable(L, -1, depotChest);
9092+
pushSharedPtr(L, depotChest);
9093+
tfs::lua::setItemMetatable(L, -1, depotChest.get());
90949094
} else {
90959095
tfs::lua::pushBoolean(L, false);
90969096
}

src/player.cpp

+16-7
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ Player::~Player()
5757
}
5858
}
5959

60+
for (const auto& [_, depot] : depotChests) {
61+
if (Cylinder* parent = depot->getRealParent()) {
62+
// remove chest from depot locker, because of possible double free when shared_ptr decides to free up the
63+
// resource
64+
parent->internalRemoveThing(depot.get());
65+
}
66+
}
67+
6068
if (depotLocker) {
6169
depotLocker->removeInbox(inbox.get());
6270
}
@@ -808,7 +816,7 @@ bool Player::isNearDepotBox() const
808816
return false;
809817
}
810818

811-
DepotChest* Player::getDepotChest(uint32_t depotId, bool autoCreate)
819+
DepotChest_ptr Player::getDepotChest(uint32_t depotId, bool autoCreate)
812820
{
813821
auto it = depotChests.find(depotId);
814822
if (it != depotChests.end()) {
@@ -824,9 +832,10 @@ DepotChest* Player::getDepotChest(uint32_t depotId, bool autoCreate)
824832
return nullptr;
825833
}
826834

827-
it = depotChests.emplace(depotId, new DepotChest(depotItemId)).first;
828-
it->second->setMaxDepotItems(getMaxDepotItems());
829-
return it->second;
835+
const DepotChest_ptr& depotChest =
836+
depotChests.emplace(depotId, std::make_shared<DepotChest>(depotItemId)).first->second;
837+
depotChest->setMaxDepotItems(getMaxDepotItems());
838+
return depotChest;
830839
}
831840

832841
DepotLocker& Player::getDepotLocker()
@@ -839,8 +848,8 @@ DepotLocker& Player::getDepotLocker()
839848
DepotChest* depotChest = new DepotChest(ITEM_DEPOT, false);
840849
// adding in reverse to align them from first to last
841850
for (int16_t depotId = depotChest->capacity(); depotId >= 0; --depotId) {
842-
if (DepotChest* box = getDepotChest(depotId, true)) {
843-
depotChest->internalAddThing(box);
851+
if (const auto& box = getDepotChest(depotId, true)) {
852+
depotChest->internalAddThing(box.get());
844853
}
845854
}
846855

@@ -3199,7 +3208,7 @@ void Player::postRemoveNotification(Thing* thing, const Cylinder* newParent, int
31993208
bool isOwner = false;
32003209

32013210
for (const auto& it : depotChests) {
3202-
if (it.second == depotChest) {
3211+
if (it.second.get() == depotChest) {
32033212
isOwner = true;
32043213
onSendContainer(container);
32053214
}

src/player.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "creature.h"
88
#include "cylinder.h"
9+
#include "depotchest.h"
910
#include "depotlocker.h"
1011
#include "enums.h"
1112
#include "groups.h"
@@ -15,7 +16,6 @@
1516
#include "town.h"
1617
#include "vocation.h"
1718

18-
class DepotChest;
1919
class House;
2020
struct Mount;
2121
class NetworkMessage;
@@ -363,7 +363,7 @@ class Player final : public Creature, public Cylinder
363363
void addConditionSuppressions(uint32_t conditions);
364364
void removeConditionSuppressions(uint32_t conditions);
365365

366-
DepotChest* getDepotChest(uint32_t depotId, bool autoCreate);
366+
DepotChest_ptr getDepotChest(uint32_t depotId, bool autoCreate);
367367
DepotLocker& getDepotLocker();
368368
void onReceiveMail() const;
369369
bool isNearDepotBox() const;
@@ -1174,7 +1174,7 @@ class Player final : public Creature, public Cylinder
11741174
std::unordered_set<uint32_t> VIPList;
11751175

11761176
std::map<uint8_t, OpenContainer> openContainers;
1177-
std::map<uint32_t, DepotChest*> depotChests;
1177+
std::map<uint32_t, DepotChest_ptr> depotChests;
11781178

11791179
std::map<uint16_t, uint8_t> outfits;
11801180
std::unordered_set<uint16_t> mounts;

src/protocolgame.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -2104,7 +2104,7 @@ void ProtocolGame::sendMarketEnter()
21042104

21052105
for (const auto& chest : player->depotChests) {
21062106
if (!chest.second->empty()) {
2107-
containerList.push_front(chest.second);
2107+
containerList.push_front(chest.second.get());
21082108
}
21092109
}
21102110

0 commit comments

Comments
 (0)