CNA-BUG-141: MediaPlayer::ProgramExit is documented as called at application exit, but nothing in CNA calls it
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). 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.
Unlike FNA, which hooks ProcessExit, CNA never calls MediaPlayer::ProgramExit outside an explicit C API export, so the music track is not released by CNA at exit and the header's statement is false.
- Identifier
CNA-BUG-141- Category
- Bug
- Subsystem
- Audio & media
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - Severity
- Low (a triage suggestion, not a project priority)
- Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- MediaPlayer::ProgramExit() (CNAEXT) and the release of MediaPlayer's music track at exit
Expected behaviour
MediaPlayer.hpp: “Releases renderer media resources if initialized. Called at application exit.” FNA's MediaPlayer static constructor registers ProgramExit on AppDomain.CurrentDomain.ProcessExit.
Actual behaviour at TARGET
No Game shutdown path, static destructor or atexit handler calls it; within the modules the only caller is the C API export cna_media_player_program_exit_ext in CnaCApiMediaPlayer.cpp. Unless the game stops the music itself, the music track (a raw pointer in MediaPlayer.cpp) is therefore not destroyed at exit, and the namespace-scope music audio is released during static destruction in an order unspecified relative to the mixer's own statics. When a host does call ProgramExit, it destroys the track but leaves the state Playing. No crash was traced to this; the defect is the missing exit hook the header promises.
Source locations
modules/media/include/Microsoft/Xna/Framework/Media/MediaPlayer.hpp— ProgramExit documentationmodules/media/src/Xna/MediaPlayer.cpp— MediaPlayer::ProgramExit; the g_musicTrack and g_musicAudio staticsmodules/c-api/src/CnaCApiMediaPlayer.cpp— cna_media_player_program_exit_ext, the only caller
Evidence
Checked by reading at 009d40f5; caller search over modules and tools excluding tests. FNA read at FNA-XNA/FNA b3551247. Not executed; no exit-time failure was observed or reproduced.
Independent re-verification: Checked by reading at 009d40f5; caller search over modules, tools and tests. The only test that calls ProgramExit is the pure-C smoke test MediaPlayerSmoke.c, which calls cna_media_player_program_exit_ext as an ordinary call after earlier plays and only requires CNA_RESULT_SUCCESS; no test checks that the music track is released, that the state changes, or that an exit hook exists. FNA read at FNA-XNA/FNA b3551247. Not executed; no exit-time failure was observed or reproduced.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
No test calls ProgramExit or checks exit-time release of the music track.
Regression test
Either register the call (for example from Game disposal or an atexit handler installed on first Play) and test that the track is released and the state is Stopped, or change the header to say the host must call it.
Blast radius
Games that exit while music is playing; the operating system reclaims the memory, so the practical effect is limited to exit-time ordering and leak reports. C API hosts that call the export are covered.
Workaround
Call MediaPlayer::Stop() (or ProgramExit()) before leaving Run().
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- Internals
- Media module: playback state
- Maintainer workflow
- Debug shutdown and lifetime: failure shapes
- Known issues
- Bug index