CNA-BUG-183: The SDL3 file-dialog and tray-entry trampolines call application callbacks without a try/catch, so a throwing handler unwinds through SDL's C code

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

✓

Evidence basis: source-verified at the pinned commit; executed for this entry (the Evidence section names exactly what was run). 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.

ResultTrampoline and EntryClickTrampoline invoke the application's std::function directly from SDL C callbacks, so an exception escaping it crosses SDL frames (undefined behaviour, typically std::terminate).

Identifier
CNA-BUG-183
Category
Bug
Subsystem
Platforms
Status
Open
Verified against
CNA 009d40f5 (009d40f5dd085c4e674d3479675fac84b12b3e0a)
Severity
Low (a triage suggestion, not a project priority)
Evidence basis
Reproduced: executed for this entry (the Evidence section names exactly what was run)
Tests touching this area
None
Affected contract
CNA::Devices::FileDialog result callbacks and CNA::Devices::SystemTray entry-click callbacks on the SDL3 platform

Expected behaviour

CNA's own devices event contract (devices-event-contract.md, section 6, Exception semantics) states the decided policy: an unhandled exception escaping a user-supplied handler must never propagate across a C callback boundary, and the normative rule is log-and-continue, catching at the C-callback or thread-entry boundary and making the event observable. The Accelerometer and Gyroscope dispatch path follows it. FileDialog.hpp and SystemTray.hpp neither state that handlers must not throw nor catch on the caller's behalf.

Actual behaviour at TARGET

ResultTrampoline in Sdl3SystemServices.cpp builds the path list and calls context->callback(paths); EntryClickTrampoline in Sdl3Tray.cpp calls (*callback)(). Both are passed to SDL as C function pointers and have no try/catch. FileDialog.hpp notes the result may arrive “on a different thread than the one the call” was made on.

Source locations

Evidence

Checked by reading at 009d40f5; the file-dialog half was also executed (see below), the tray half was only read.

Independent re-verification: Checked by reading at 009d40f5; not executed. The contract is CNA's own devices event contract, section 6 of which is titled 'decided but not yet uniformly implemented' and lists sensor paths only, so the SDL3 dialog and tray boundaries are an unlisted instance of that policy. Neither devices-ext wrapper adds a catch (FileDialog.cpp passes the callback straight to the platform and SystemTray.cpp forwards it), so a handler's exception reaches the trampoline. What SDL's C frames then do with it (undefined behaviour, typically std::terminate) depends on the toolchain and was not run.

Independent re-verification: Checked by reading at 009d40f5. Reproduced for the file dialog by the audit: TARGET's Sdl3SystemServices.cpp was compiled with g++ -O0 and linked with a system SDL 3.4.0 (not CNA's pinned SDL commit); Sdl3Dialogs::ShowOpenFileDialog was called with a callback that throws, SDL's zenity driver delivered the (cancelled) result on its own thread through ResultTrampoline, and the process ended with 'terminate called after throwing an instance of std::runtime_error' (SIGABRT). The SystemTray entry-click trampoline was read but not run. Neither devices-ext wrapper adds a catch (FileDialog.cpp passes the callback straight to the platform and SystemTray.cpp forwards it). What SDL's C frames do with an exception delivered on the calling thread depends on the toolchain: with default x86-64 unwind tables it unwinds through them, without unwind tables it terminates.

Focused reproduction

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

Current tests

The trampolines are not driven by any test (see CNA-VGAP-007).

Regression test

A test that invokes each trampoline with a throwing callback and asserts the exception is contained (logged or reported); the fix is a catch-all around the call.

Blast radius

Applications whose dialog or tray handlers can throw, on the SDL3 platform.

Workaround

Catch every exception inside the handler.

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

Known issues
Bug index