CNA-GAP-001: ContentLoadException derives from std::runtime_error, not System::Exception, so no Sharp Runtime catch clause spans CNA's XNA exceptions

CNA snapshot 009d40f5  ·  Known Issues › Functional gaps  ·  source links pinned to 009d40f5

✓

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 XNA, where every framework exception is a System.Exception, CNA's ContentLoadException (deliberately) derives from std::runtime_error, so catch (const System::Exception&) misses content-load failures; only std::exception spans the framework.

Identifier
CNA-GAP-001
Category
Functional gap
Subsystem
Core & runtime
Status
Narrowed (partially fixed; describes only what survives)
Verified against
CNA 009d40f5 (009d40f5dd085c4e674d3479675fac84b12b3e0a)
Evidence basis
Source-verified: read at TARGET, not executed
Tests touching this area
Yes: see Current tests
Affected contract
Microsoft::Xna::Framework::Content::ContentLoadException and the catchability of CNA exceptions through System::Exception

Expected behaviour

In XNA 4.0 ContentLoadException derives from System.Exception like every other framework exception, so a port that catches Exception around Content.Load expects the C++ equivalent, catch (const System::Exception&), to see it.

Actual behaviour at TARGET

At TARGET the XNA-named exceptions of graphics (DeviceLostException, DeviceNotResetException, NoSuitableGraphicsDeviceException), audio, gamer services, net, devices and the content pipeline derive from System::Exception. ContentLoadException in ContentLoadException.hpp derives from std::runtime_error, and its header states that this is deliberate ("because a great deal of code catches std::runtime_error around content loads"); it stores its own inner cause because that base has none. The CNA-specific CNA::Platform::PlatformException also derives from std::runtime_error, while CNA::CNAException derives from System::Exception. Sharp Runtime's System::Exception derives from std::exception, not std::runtime_error (Sharp Runtime next at 41b918c9, not pinned by TARGET), and the math module throws standard exception types (see the exception-families entry).

So a handler for System::Exception does not see content-load failures, a handler for std::runtime_error does not see the System::Exception family, and only catch (const std::exception&) spans the framework.

Fixed since the earlier record: the three graphics exceptions used to derive from std::runtime_error; they now derive from System::Exception and GraphicsExceptionTests.cpp pins that. What remains is a documented, deliberate narrowing, not a defect.

Source locations

Evidence

Checked by reading at 009d40f5; nothing was built or executed for this entry. The bases were read from every public exception header under modules/*/include; the deliberate choice is stated in the ContentLoadException header and pinned by ContentRuntimeContractTests. The graphics fix is pinned by GraphicsExceptionTests.

Focused reproduction

Illustrative; not compiled or run for this entry.

try {                                          // inside a Game subclass
    auto texture = getContentProperty().Load<Texture2D>("missing");
} catch (const System::Exception& e) {
    // never reached for a missing asset: ContentLoadException is not a System::Exception
} catch (const std::exception& e) {
    // reached
}

Current tests

GraphicsExceptionTests asserts that the graphics exceptions are caught as System::Exception and as std::exception; ContentRuntimeContractTests asserts that ContentLoadException is caught as std::runtime_error. No test documents that it is not a System::Exception.

Regression test

Not a defect to fix. If the base is ever changed to System::Exception, the std::runtime_error expectation in ContentRuntimeContractTests must change with it and every content throw site that is caught as runtime_error must be reviewed.

Blast radius

C++ code ported from XNA that catches Exception around content loads, and generic error handlers written against System::Exception. The C ABI is unaffected: its barrier maps ContentLoadException explicitly to CNA_RESULT_IO.

Workaround

Catch ContentLoadException explicitly around content loads, and use std::exception only at a top-level boundary.

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