Refactor ClientCard memory management #3131
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors ClientCard lifetime management to be owned by ClientField (via std::unique_ptr storage), replacing scattered new/delete sites and reducing the risk of leaking cards when they fail to be inserted into a field container.
Changes:
- Introduces
ClientField::CreateCard()/ClientField::DestroyCard()and a privatecards_owner container. - Updates
DuelClientto allocate/free cards throughClientFieldinstead ofnew/delete. - Makes
ClientCardfield-aware (stores aClientField*) and routes certain operations through it.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| gframe/duelclient.cpp | Switches card allocation/deallocation to CreateCard()/DestroyCard() in multiple message handlers. |
| gframe/client_field.h | Adds CreateCard()/DestroyCard(), includes <memory>, and introduces the owning cards_ container. |
| gframe/client_field.cpp | Implements CreateCard()/DestroyCard() and removes manual deletion loops in Clear()/destructor. |
| gframe/client_card.h | Replaces default ctor with ClientCard(ClientField*) and stores a ClientField*. |
| gframe/client_card.cpp | Uses field_ for field interactions and creates overlay cards via field_->CreateCard(). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
Even after this change, there is still some potential memory-safety issues. In For example, in a tag duel replay, if the user opens the opponent's Deck view before the first player's turn ends, the end-of-turn tag swap will update the Deck contents. The already-open card list can then display incorrect cards, or potentially reference cards that have been destroyed. Actually, our support for viewing zones such as the Graveyard during replay is already fragile. We currently avoid stale |
|
Better than nothing, I suppose. |
mercury233
left a comment
There was a problem hiding this comment.
My understanding is that the goal of this PR is to reduce the risk of memory leaks, but it doesn't address the existing dangling pointer/use-after-free risks, and may actually increase them. If that's the case, I don't think it should be merged now.
Can you give any example on how this PR "increase" dangling pointer? |
|
Memory leak is a big problem by itself. If you are trying to say: I am afraid that this is not very convincing. |
|
Memory leaks are probably the least serious issue among the "big problems", especially on the client side. A I'm not saying memory leaks shouldn't be fixed, nor am I saying it's impossible to fix both memory leaks and UAFs at the same time. My point is that UAFs are much more dangerous, and in many cases, strategies for eliminating memory leaks can be at odds with strategies for preventing UAFs. For this particular PR, I can't point to a specific place where it increases the risk of UAF. Just as static analysis and unit tests can't catch every bug, I can't prove that it does. My concern is that I don't think it's the right direction, or at least not the direction I would choose to pursue. |
First of all: About UAFThe root cause of UAF is creating and destroying objects at any place without being noticed by other functions. The main purpose of this PR: By using an array of smart pointers to keep of all active cards, this PR is actually the first step of fixing UAF. |
Again, can you give any example on "strategies for eliminating memory leaks can be at odds with strategies for preventing UAFs"? |
|
A quick skim of the code wasn't enough for me to fully understand how this PR works. For the reasons I mentioned earlier, I'm not planning to dig into it in depth for now. Centralizing ownership/management may be the first step toward fixing UAFs, or it may be the first step toward introducing even more bugs (though I also feel the former is more likely).
One common approach to fixing memory leaks is to add more |
I'm no longer voting against it. I'll just not vote.
This PR fix memory leaks by using a vector of smart pointers managed by ClientField. If you really worry about use-after-free, then don't free any ClientCard object as long as ClientField is alive. I suggest that remove all |
Problem
MSG_MOVE, pl = 0
If
clis wrong,dField.AddCardwill fail.The pointer
pcardwill not be placed to any container, and it is lost after leaving the block.It will causes memory leak.
Reason
All
ClientCardobject should be managed byClientField, instead of creating newClientCardobject at any place.Solution
ClientField
Now it will keep track of
ClientCardunique_ptr in the private membercards_.ClientCard
Now it has a pointer to the
ClientFieldobject.@Wind2009-Louse