Skip to content

fix(windows): stop DXGI enumeration on any failure - #5893

Open
abbradar wants to merge 2 commits into
LizardByte:masterfrom
abbradar:fix/dxgi-enumeration-errors
Open

abbradar wants to merge 2 commits into
LizardByte:masterfrom
abbradar:fix/dxgi-enumeration-errors

Conversation

@abbradar

Copy link
Copy Markdown

Description

The EnumAdapters1()/EnumOutputs() loops only stopped on DXGI_ERROR_NOT_FOUND and used the returned pointer after any other error, which crashed Sunshine and dxgi-info in sessions without a desktop. Log the error and stop instead.

I caught this when I tried to run Sunshine via SSH.

Screenshot

Issues Fixed or Closed

Roadmap Issues

Testing

It no longer crashes.

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • refactor: Code change that neither fixes a bug nor adds a feature
  • perf: Code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit
  • BREAKING CHANGE: Introduces a breaking change (can be combined with any type above)

Checklist

  • Code follows the style guidelines of this project
  • Code has been self-reviewed
  • Code has been commented, particularly in hard-to-understand areas
  • Code docstring/documentation-blocks for new or existing methods/components have been added or updated
  • Tests have been added or updated for new or modified functionality, including regression tests for bug fixes

AI Usage

See our AI usage policy.

  • AI tools were used while preparing this PR

Debugged and found all places to patch with Claude Opus 5.5.

@abbradar

Copy link
Copy Markdown
Author

TBH, not too happy with whiles and post-loop error checks just to keep SonarQube happy; maybe there's a better way to implement this?

The EnumAdapters1()/EnumOutputs() loops only stopped on DXGI_ERROR_NOT_FOUND
and used the returned pointer after any other error, which crashed Sunshine
and dxgi-info in sessions without a desktop. Log the error and stop instead.
@abbradar
abbradar force-pushed the fix/dxgi-enumeration-errors branch from f9a5d39 to fd55804 Compare November 7, 2026 18:06
@sonarqubecloud

sonarqubecloud Bot commented Nov 7, 2026

Copy link
Copy Markdown

@ReenigneArcher ReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head fd55804b873b2f1244d97f15d624324d55819a9f against master at ee31a6aa252153df7c9f693ca62e6167cf39ca3f. The original unchecked-error path is still present on the target branch, so this fix remains relevant. The success guards address invalid-result use, but please resolve the partial display-list regression and add the required automated regression coverage before merging.

Validation: both changed C++ files passed UCRT64 GCC 16.2 syntax checks using the existing workspace dependency headers; the complete diff passed git diff --check. An extracted-function harness reproduced three partial-list failures on this head, and all seven scenarios passed with the suggested early returns. Full Sunshine tests and the SSH/session-without-desktop scenario were not run locally.

Verification limits: CI, CodeQL, common lint, and GH-Pages workflows await maintainer approval. The failed GH-Pages Read the Docs build 35722539 timed out waiting for check runs; its log does not show a change-related compilation failure. SonarCloud and the Sunshine documentation status passed. GitHub currently reports the PR mergeable.

Review completed by Codex | Model: gpt-6.1-sol | Thinking: xhigh

Comment on lines +1138 to 1144
if (FAILED(status) && status != DXGI_ERROR_NOT_FOUND) {
BOOST_LOG(error) << "Failed to enumerate DXGI outputs [0x"sv << util::hex(status).to_string_view() << ']';
}
}
if (FAILED(status) && status != DXGI_ERROR_NOT_FOUND) {
BOOST_LOG(error) << "Failed to enumerate DXGI adapters [0x"sv << util::hex(status).to_string_view() << ']';
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Discard the display list when enumeration fails

If one display has already been appended and a later EnumOutputs() or EnumAdapters1() returns an unexpected failure, these handlers only log it and display_names() returns the earlier displays as a successful, nonempty result. For example, PRIMARY succeeds and enumeration fails before the active SECONDARY display. video::refresh_displays() then replaces its cached list with [PRIMARY], cannot find SECONDARY, and resets the capture selection to PRIMARY. Returning an empty list instead lets that caller retain its previous list and active display. This also preserves the all-or-nothing requirement documented at the start of this function.

Return immediately from both unexpected-error handlers:

Suggested change
if (FAILED(status) && status != DXGI_ERROR_NOT_FOUND) {
BOOST_LOG(error) << "Failed to enumerate DXGI outputs [0x"sv << util::hex(status).to_string_view() << ']';
}
}
if (FAILED(status) && status != DXGI_ERROR_NOT_FOUND) {
BOOST_LOG(error) << "Failed to enumerate DXGI adapters [0x"sv << util::hex(status).to_string_view() << ']';
}
if (FAILED(status) && status != DXGI_ERROR_NOT_FOUND) {
BOOST_LOG(error) << "Failed to enumerate DXGI outputs [0x"sv << util::hex(status).to_string_view() << ']';
return {};
}
}
if (FAILED(status) && status != DXGI_ERROR_NOT_FOUND) {
BOOST_LOG(error) << "Failed to enumerate DXGI adapters [0x"sv << util::hex(status).to_string_view() << ']';
return {};
}

I reproduced this using the exact function from this head with fake DXGI objects: failure after an output, failure after an adapter, and output failure on a later adapter all returned [PRIMARY]. With these two returns, all seven harness scenarios passed. This was an extracted-function harness, not a hardware or full Sunshine test run.

Review completed by Codex | Model: gpt-6.1-sol | Thinking: xhigh

for (int tries = 0; tries < 2; ++tries) {
for (int x = 0; factory->EnumAdapters1(x, &adapter_p) != DXGI_ERROR_NOT_FOUND; ++x) {
int x = 0;
while (SUCCEEDED(status = factory->EnumAdapters1(x++, &adapter_p))) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Add regression coverage for the failed-enumeration paths

The PR changes six production enumeration loops but adds no automated tests. The manual SSH check does not exercise a failure after a successful result, which is the partial-list defect above. Regression tests are required for changed source behavior.

Add tests/unit/platform/windows/test_dxgi_enumeration.cpp, using ../../../tests_common.h in the test include group and the existing GoogleTest framework. Introduce an injectable factory/adapter seam or a shared production helper so these tests exercise the actual enumeration code without requiring SSH or a particular GPU. There is currently no enumeration injection seam, so a test that merely copies the loops would not protect the fix.

Concrete cases for DxgiEnumerationTest:

  • Make the first adapter call fail with E_FAIL, and the first output call fail with DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; assert no descriptor/pointer access occurs after failure and the call terminates.
  • Return a capturable PRIMARY first, then fail adapter enumeration, output enumeration, or output enumeration on a later adapter; assert the result is empty.
  • Return PRIMARY and SECONDARY followed by DXGI_ERROR_NOT_FOUND; assert both names remain and normal exhaustion produces no error log.
  • Exercise the initialization and diagnostic-tool paths through the same seam/helper, checking that unexpected failures stop enumeration and report the appropriate error.

Document the failure contract in Doxygen alongside the changed methods/helper. A focused test command after building the test target is:

C:\msys64\msys2_shell.cmd -defterm -here -no-start -ucrt64 -c './cmake-build-release/tests/test_sunshine.exe --gtest_filter=DxgiEnumerationTest.*'

These are proposed repository tests; they have not been added or run. The separate review harness covered the seven display-list scenarios described above.

Review completed by Codex | Model: gpt-6.1-sol | Thinking: xhigh

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants