-
Notifications
You must be signed in to change notification settings - Fork 145
bugfix(particlesystem): Prevent double-destroy and use-after-free in ParticleSystem::destroy #2137
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
base: main
Are you sure you want to change the base?
bugfix(particlesystem): Prevent double-destroy and use-after-free in ParticleSystem::destroy #2137
Conversation
…ParticleSystem::destroy
|
| Filename | Overview |
|---|---|
| GeneralsMD/Code/GameEngine/Source/GameClient/System/ParticleSys.cpp | Added double-destroy guard and null pointer safety to prevent use-after-free crashes during shutdown |
Sequence Diagram
sequenceDiagram
participant W3DTankDraw
participant ParticleSystem
participant SlaveSystem
participant ParticleSystemManager
Note over W3DTankDraw: Holds raw pointers:<br/>m_treadDebrisLeft,<br/>m_treadDebrisRight
rect rgb(255, 240, 240)
Note over ParticleSystemManager,SlaveSystem: Problem Scenario (Before Fix)
ParticleSystem->>ParticleSystem: destroy() called
ParticleSystem->>ParticleSystem: m_isDestroyed = true
ParticleSystem->>SlaveSystem: destroy()
ParticleSystem->>ParticleSystem: update() returns false
ParticleSystemManager->>ParticleSystem: deleteInstance()
Note over ParticleSystem: Memory freed (0xDEADBEEF)
W3DTankDraw->>W3DTankDraw: ~W3DTankDraw()
W3DTankDraw->>W3DTankDraw: tossEmitters()
W3DTankDraw->>ParticleSystem: destroy() on freed memory
Note over ParticleSystem: CRASH! Use-after-free
end
rect rgb(240, 255, 240)
Note over ParticleSystemManager,SlaveSystem: Fixed Scenario (After Fix)
ParticleSystem->>ParticleSystem: destroy() called
ParticleSystem->>ParticleSystem: m_isDestroyed = true
ParticleSystem->>SlaveSystem: destroy()
ParticleSystem->>ParticleSystem: m_slaveSystem = nullptr
ParticleSystem->>ParticleSystem: update() returns false
ParticleSystemManager->>ParticleSystem: deleteInstance()
Note over ParticleSystem: Memory freed
W3DTankDraw->>W3DTankDraw: ~W3DTankDraw()
W3DTankDraw->>W3DTankDraw: tossEmitters()
W3DTankDraw->>ParticleSystem: destroy() on freed memory
ParticleSystem->>ParticleSystem: Early return (m_isDestroyed check)
Note over ParticleSystem: Safe! No crash
end
|
Hmm yeah this looks a bit risky. I will look into it. |
|
Is there a way to reproduce this issue? |
Reproduction Steps:
Should see something like Access violation writing to 0xDEADBEEF + offset |
Summary
ParticleSystem::destroy()if already destroyedm_slaveSystempointer after calling destroy on slaveProblem
During shutdown,
W3DTankDraw::tossEmitters()can calldestroy()on particle systems that have already been freed byParticleSystemManager::update(). This causes a crash in debug builds where freed memory is filled with0xDEADBEEF.The crash occurs because:
m_treadDebrisLeft,m_treadDebrisRight)ParticleSystemManager::update()deletes systems afterdestroy()is called and particles finishtossEmitters()on the now-freed memoryThis fix is just to return if m_isDestroyed is truthy, which prevents the crash for me.
Notes
W3DTankDraw's pointers can become dangling when ParticleSystemManager deletes the systems. Are there any better ways to handle this? eg
Testing