CNA-BUG-181: Sdl3Platform reports the nativeFileDialog capability on iOS and web builds, where SDL has no usable file-dialog backend

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

✓

Evidence basis: source-verified at the pinned commit; inferred from the source (the behaviour was not run); 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.

The SDL3 platform sets nativeFileDialog unconditionally, so on iOS and the web the platform says a dialog can be shown while FileDialog::getIsSupportedProperty says it cannot, and FileDialog::Show* reach SDL, which fails the request.

Identifier
CNA-BUG-181
Category
Bug
Subsystem
Platforms
Status
Open
Verified against
CNA 009d40f5 (009d40f5dd085c4e674d3479675fac84b12b3e0a)
Severity
Low (a triage suggestion, not a project priority)
Evidence basis
Inferred (strong): follows from the code, but the behaviour was not run
Tests touching this area
Yes: see Current tests
Affected contract
CNA::Platform::PlatformCapabilities::nativeFileDialog as reported by the SDL3 platform (Sdl3Platform::GetCapabilities); CNA::Devices::FileDialog::getIsSupportedProperty and ShowOpenFile, ShowSaveFile, ShowOpenFolder

Expected behaviour

PlatformCapabilities.hpp: nativeFileDialog means "A native file or folder dialog can be shown", and a capability that is not supported is refused, never silently ignored. FileDialog.hpp records that SDL has no dialog backend for iOS or Web/Emscripten and promises that getIsSupportedProperty() "reports this honestly per platform"; a Show* call there should take the documented unavailable path.

Actual behaviour at TARGET

Sdl3Platform::GetCapabilities in Sdl3Platform.cpp sets capabilities.nativeFileDialog = true with no target condition, although primarySelection in the same function is guarded for Emscripten and Android and the X11 and Wayland platforms derive the flag from their dialog service. FileDialog::getIsSupportedProperty compensates with its own build-target switch (Web and iOS return false), but the three Show* functions, and any other reader of the capability, gate on the capability alone, so on those targets the request reaches Sdl3Dialogs and SDL. On iOS SDL builds its dummy dialog, which reports failure through the callback at once; in a browser SDL's Unix dialog code finds neither a desktop portal nor a helper process and does the same. ResultTrampoline in Sdl3SystemServices.cpp turns SDL's null file list into an empty list, so the caller sees the same answer as a cancel, before Show* returns. That is also what FileDialog's own unavailable path delivers (ReportUnavailable calls back with an empty list immediately), so the result and timing a Show* caller observes are the same on both paths; what contradicts itself is the two public answers, the capability (true) and getIsSupportedProperty (false). The null parent window the candidate also lists is a documented note in FileDialog.hpp and is not part of this defect.

Source locations

Evidence

Checked by reading the CNA sources at 009d40f5; not executed on iOS or in a browser. SDL's per-platform dialog selection was read in a sibling SDL checkout at exactly the revision TARGET pins (third_party/SDL at cbe3fbe9; re-read for the adversarial audit in CMakeLists.txt and include/build_config/SDL_build_config_ios.h): dialog sources are selected for Android, Unix, Haiku, Windows and macOS, and SDL_build_config_ios.h defines SDL_DIALOG_DUMMY, whose implementation calls the callback with a null list. The web statement relies on FileDialog.hpp's own record and on a browser having no portal or helper process; which SDL dialog sources an Emscripten build compiles was not settled.

Independent re-verification: Checked by reading the CNA sources at 009d40f5; not executed on iOS or in a browser. SDL's per-platform dialog selection was read in a sibling SDL checkout at exactly the revision TARGET pins (SDL at cbe3fbe9; re-read for the adversarial audit in CMakeLists.txt and include/build_config/SDL_build_config_ios.h): dialog sources are selected for Android, Unix, Haiku, Windows and macOS, and SDL_build_config_ios.h defines SDL_DIALOG_DUMMY, whose implementation calls the callback with a null list. For the web, a locally built Emscripten SDL 3 tree a few weeks newer than the pin shows that Emscripten's CMake platform file sets UNIX, so SDL compiles its Unix (portal and zenity) dialog sources there; at run time they find neither and call the callback with a null list at once, like the iOS dummy. FileDialog.hpp's statement that SDL has no dialog backend for Web is therefore imprecise as to the selection, but the conclusion that no dialog can be shown in a browser holds. The Emscripten reading was not made at the pinned revision.

Focused reproduction

// Illustrative; iOS or Emscripten build with the SDL3 platform and CNA_DEVICES=ON; not run.
const bool capability =
    CNA::Platform::GetCurrentPlatform().GetCapabilities().nativeFileDialog;   // true
const bool supported = CNA::Devices::FileDialog::getIsSupportedProperty();    // false
CNA::Devices::FileDialog::ShowOpenFile(
    [](const std::vector<std::string>& files) { /* called with an empty list */ });

Current tests

PlatformConformanceTests.cpp and Sdl3PlatformTests.cpp check, on the desktop host that runs them, that each service is non-null exactly when its capability is set; FileDialogTests.cpp runs against a canned platform. No test built for iOS or the web asserts the capability set there.

Regression test

Report nativeFileDialog only for builds whose SDL has a real dialog backend, derive FileDialog::getIsSupportedProperty from the capability alone, and compile a capability test into the iOS and Emscripten test builds that expects it to be false.

Blast radius

iOS and web builds on the SDL3 platform: code that reads the platform capability sees a file-dialog service that cannot show anything, and FileDialog::Show* callers get an immediate empty result instead of the documented unavailable path (same value, earlier timing). Desktop and Android builds are unaffected.

Workaround

Gate file-dialog UI on FileDialog::getIsSupportedProperty(), not on the platform capability.

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

Known issues
Bug index