CNA-BUG-086: GameComponent::Dispose(true) does not remove the component from Game.Components

CNA snapshot 009d40f5  ·  Known Issues › Current bugs  ·  source links pinned to 009d40f5

✓

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

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.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

Maintainer workflow
Case study: components
Known issues
Bug index