CNA-BUG-253: SdlGpu_ConstructorExceptionSafety aborts with a double free, a defect CNA's own record calls real and leaves unfixed

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

✓

Evidence basis: source-verified at the pinned commit; recorded by CNA's own run (not repeated here); tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit c1c316b9; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.

CNA's records say the classic SDL_GPU constructor-failure test aborts with 'double free detected in tcache 2'; every pass recorded since is a static-link build, and CNA diagnosed the same abort in an FNA3D test as a shared-library link-line defect.

Identifier
CNA-BUG-253
Category
Bug
Subsystem
Graphics & renderers
Status
Open
Verified against
CNA c1c316b9 (c1c316b9c7a846ce8002809c151fcd1af14942c9)
Severity
Medium (a triage suggestion, not a project priority)
Evidence basis
Recorded by CNA: CNA's own recorded run, not repeated here
Tests touching this area
Yes: see Current tests
Affected contract
CNA::Internal::Renderers::SdlGpu::SdlGpuRenderer construction, under the transactional-construction contract REMED-GFX-028 states for it

Expected behaviour

The regression test's own header states the contract: “Every failed constructor must balance acquisition/release callbacks, leave no window-registry entry, preserve the caller-owned SDL_Window, and permit an immediately succeeding renderer”, with resource callbacks that make leaks and double-destruction observable. A double free on a failed construction violates it.

Actual behaviour at TARGET

The registered CTest SdlGpu_ConstructorExceptionSafety (target cna_test_sdlgpu_constructor_exception_safety, sdlgpu_constructor_exception_safety_test.cpp) aborts with free(): double free detected in tcache 2. CNA's plan record says the same binary 'built from the unmodified renderer sources (changes stashed, rebuilt from ccache) aborts identically - not introduced here, not investigated further', and its backlog calls it 'A real bug, not test debt', with an owner decision dated 2026-09-23 to fix it later as a small targeted bugfix. The latest record that runs the classic set on Linux, SMG-0043 (plan_sdlgpu_modern_graphics.md), still counts “the recorded constructor-exception double free” among its 26 failures. The record does not name the freeing site, so neither does this entry.

What the later records add: RRC-020 (plan_renderer_cleanup.md) records the test passing on the same private display in a static (CNA_SHARED_LIBRARY=OFF) multi-renderer tree, and CNA's macOS qualification (statically linked) records the whole SDL_GPU tree passing. On every non-Apple toolchain the test links CNA and, in addition, an explicit $<LINK_GROUP:RESCAN,…> of the static graphics archive cycle (the SDL_GPU examples' CMakeLists.txt); in a CNA_SHARED_LIBRARY=ON build, the Linux GCC and Clang default, CNA is libcna.so, and SharedRuntimeLibrary.cmake explains that archives on a consumer's link line beside libcna.so give a static object two copies. CNA's MSR-020 record (plan_samples_multirenderer.md) diagnosed exactly that as the exit-time double free of Fna3d_Device_Lifetime (two registrations of TouchPanel::gestures_' teardown) and removed the rescan from that test. Whether the SDL_GPU abort has the same cause is not recorded; by reading it is the likeliest one, which would make it a defect of the test's link line in shared-library builds rather than of the renderer. SDL_GPU is declared Supported (not Experimental) in GraphicsBackendMaturity.hpp.

Source locations

Evidence

Read at c1c316b9: the test registration, the test's header and CNA's plan record. Not executed: the abort is recorded by CNA, not reproduced for this entry, and the cause was not isolated (CNA's record says it was not investigated further). Found by the independent adversarial review of the graphics entries (a reviewer noticed it appeared only as a test name inside a cluster of failing classic SDL_GPU tests) and re-verified against the plan text by the orchestrator.

Independent re-verification: Read at c1c316b9: the test registration, the test source, the SdlGpuRenderer constructor transaction and CNA's plan records (SMG-0041/SMG-0042 backlog, PSG-0009, STREETS-0008, SDLGPU-56). Not executed: the abort is recorded by CNA, not reproduced for this entry, and the freeing site was not located by reading.

Re-verified at c1c316b9: read the test's link setup (cna_sdlgpu_test, cna_graphics_archive_cycle), SharedRuntimeLibrary.cmake and the records SMG-0043, RRC-020, MSR-020 and AM4-039/AM4-208; not executed. Every pass recorded since the abort is a static-link build; no record shows the test passing in a shared-library build.

Focused reproduction

No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.

Current tests

The test itself is the regression test and is registered; CNA's latest Linux run of the classic set (SMG-0043) still records it failing. CNA's earlier SDLGPU-56 result (2026-09-09) and its later static-link runs (RRC-020 on Linux, the macOS qualification) record it passing.

Regression test

The existing SdlGpu_ConstructorExceptionSafety, run in a CNA_SHARED_LIBRARY=ON tree (the configuration in which only failures are recorded) and kept in a lane that runs it under a double-free or leak-checking allocator.

Blast radius

If the abort is the link-line duplication described above, only this test executable is affected, in shared-library builds; if it is in the renderer, the classic SDL_GPU renderer (declared Supported in GraphicsBackendMaturity.hpp) on a construction that fails part-way. Which of the two it is has not been established.

Workaround

No workaround is known.

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

Maintainer workflow
Fix a renderer bug: triage
Known issues
Bug index