Fix wrong RwFrame freed when replacing a model atomic - #5298
Open
Flashmyname wants to merge 1 commit into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes a long-standing cleanup bug in the GTA:SA model-replacement path where CFileLoader_SetRelatedModelInfoCB could destroy the incoming clone’s RwFrame instead of the replaced atomic’s frame, leading to use-after-free during the atomic walk and leaving the replaced atomic’s frame unfreed.
Changes:
- Capture the replaced atomic’s frame (
pOldAtomic->object.object.parent) before replacement. - Destroy the replaced atomic’s frame alongside
RpAtomicDestroy(pOldAtomic)(instead of destroyingpOldFrame, which belongs to the incoming clone that gets destroyed by the caller).
Note for commit message quality: please include the motivation (issue/PR linkage) and the concrete test evidence/results from the PR description (e.g., frame/atomic counters and soak test duration) in the commit message(s), so future archaeology doesn’t depend on PR metadata.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Flashmyname
force-pushed
the
fix/4956-model-atomic-frame
branch
from
August 31, 2026 22:46
879256f to
300be0f
Compare
CFileLoader_SetRelatedModelInfoCB freed pOldFrame, the incoming clone's frame that the caller destroys anyway, while the replaced atomic's own frame leaked. Take the frame from the old atomic instead, the way CAtomicModelInfo::DeleteRwObject does. Part of multitheftauto#4956
Flashmyname
force-pushed
the
fix/4956-model-atomic-frame
branch
from
September 2, 2026 14:26
300be0f to
e9ec047
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CFileLoader_SetRelatedModelInfoCBfrees the wrongRwFramewhen a model's atomic is replaced. It destroyspOldFrame- the frame of the atomic being installed, which belongs to the caller's clone - while the replaced atomic's own frame is never freed.Take the frame from the replaced atomic instead, and free it with that atomic. This is what
CAtomicModelInfo::DeleteRwObject(0x4C4440) does: readatomic->object.object.parent, thenRpAtomicDestroy+RwFrameDestroy.Dropping
RwFrameDestroy(pOldFrame)leaks nothing -pOldFramestays in the clone's hierarchy, andReplaceAllAtomicsInModeldestroys that clump immediately after the walk (CRenderWareSA.cpp:558).The damaged atomic has a leak of its own -
SetDamagedAtomicoverwrites the previous one without freeing it - but that is pre-existing and outside the block this touches, so it is left alone here.Motivation
Part of #4956. Follow-up to #1265 (
ad78737), which added this cleanup for #359 and picked the wrong frame:pOldFramewas in scope, the replaced atomic's was not. The game's ownCFileLoader::SetRelatedModelInfoCB(0x537150) frees neither, which is the leak #359 reported.Freeing
pOldFrameearly was also unsafe:RwFrameDestroyleaves attached objects' parent pointers dangling, so on a DFF whose clone parents several atomics to one frame, a later iteration of the same walk reads a freed frame atCFileLoaderSA.cpp:197.Test plan
engineReplaceModeland stream them in and out repeatedly.Checklist