CNA-BUG-086: GameComponent::Dispose(true) does not remove the component from Game.Components
Evidence basis: source-verified at the pinned commit. Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
XNA 4.0's GameComponent.Dispose(bool) removes the component from its Game's Components before raising Disposed; CNA only raises Disposed, so a component disposed to retire it keeps being updated and drawn.
- Identifier
CNA-BUG-086- Category
- Bug
- Subsystem
- Core & runtime
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - Severity
- Medium (a triage suggestion, not a project priority)
- Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- None
- Affected contract
- Microsoft::Xna::Framework::GameComponent::Dispose(bool) (and DrawableGameComponent::Dispose(bool), which calls it)
Expected behaviour
XNA 4.0 (IL of GameComponent.Dispose(bool)): when disposing, under a lock on the component, if (Game != null) Game.Components.Remove(this), then raise Disposed.
Actual behaviour at TARGET
GameComponent.cpp sets disposed_ and raises Disposed; it never touches Game.Components. Update and Draw have no disposed guard, so the XNA idiom "dispose the pause menu to make it go away" leaves the component registered and running.
Source locations
modules/runtime/src/GameComponent.cpp— GameComponent::Dispose(bool)modules/runtime/src/DrawableGameComponent.cpp— DrawableGameComponent::Dispose(bool) forwards to it
Evidence
Checked by reading the named sources at 009d40f5; nothing was built or executed for this entry. XNA behaviour from the genuine XNA 4.0 Game IL. The site's components deep dive already warns about this divergence.
Focused reproduction
// Illustrative; not compiled or run for this entry.
auto menu = std::make_shared<PauseMenu>(game); // a DrawableGameComponent
game.getComponentsProperty().Add(menu);
// ... later, to close it the XNA way:
menu->Dispose();
// XNA: removed from Components, no more Update/Draw.
// CNA: still in Components; Update/Draw keep running on a disposed object.
Current tests
GameComponentTests.cpp and DrawableGameComponentTests.cpp do not dispose a registered component.
Regression test
A test that adds a component, disposes it, and asserts that Components.Contains is false and that ComponentRemoved was raised before Disposed.
Blast radius
Games that retire components by disposing them. Games that call Components.Remove explicitly are unaffected.
Workaround
Remove the component from Game.Components before disposing it.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- Maintainer workflow
- Case study: components
- Deep dives
- Components: disposal does not unregister
- Known issues
- Bug index