Skip to content

Fix wrong RwFrame freed when replacing a model atomic - #5298

Open
Flashmyname wants to merge 1 commit into
multitheftauto:masterfrom
Flashmyname:fix/4956-model-atomic-frame
Open

Fix wrong RwFrame freed when replacing a model atomic#5298
Flashmyname wants to merge 1 commit into
multitheftauto:masterfrom
Flashmyname:fix/4956-model-atomic-frame

Conversation

@Flashmyname

@Flashmyname Flashmyname commented Aug 31, 2026

Copy link
Copy Markdown

Summary

CFileLoader_SetRelatedModelInfoCB frees the wrong RwFrame when a model's atomic is replaced. It destroys pOldFrame - 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: read atomic->object.object.parent, then RpAtomicDestroy + RwFrameDestroy.

Dropping RwFrameDestroy(pOldFrame) leaks nothing - pOldFrame stays in the clone's hierarchy, and ReplaceAllAtomicsInModel destroys that clump immediately after the walk (CRenderWareSA.cpp:558).

The damaged atomic has a leak of its own - SetDamagedAtomic overwrites 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: pOldFrame was in scope, the replaced atomic's was not. The game's own CFileLoader::SetRelatedModelInfoCB (0x537150) frees neither, which is the leak #359 reported.

Freeing pOldFrame early was also unsafe: RwFrameDestroy leaves 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 at CFileLoaderSA.cpp:197.

Test plan

  1. Replace atomic models with engineReplaceModel and stream them in and out repeatedly.
  2. With counters compiled into the callback, over 200 replacements: it read an already-destroyed frame 76 times before the change and 0 times after, and frames freed now match atomics freed exactly (216 / 216).
  3. 25 minutes with 2061 replaced models at the 256 MB streaming limit - no crash.

Checklist

  • Your code should follow the coding guidelines.
  • Smaller pull requests are easier to review. If your pull request is beefy, your pull request should be reviewable commit-by-commit.

Copilot AI lite review requested due to automatic review settings August 31, 2026 22:39

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 destroying pOldFrame, 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
Flashmyname force-pushed the fix/4956-model-atomic-frame branch from 879256f to 300be0f Compare August 31, 2026 22:46
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
Flashmyname force-pushed the fix/4956-model-atomic-frame branch from 300be0f to e9ec047 Compare September 2, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants