niels9001's Description of Work
Summary of the Pull Request
Prevent Settings search from passing queries that normalize to empty or whitespace-only text into fuzzy matching, and make the shared matcher return its existing no-match result for whitespace-only queries.
PR Checklist
- [x] Communication: Scoped to the requested atomic Settings search-safety audit follow-up; submitted as a draft.
- [x] Tests: Added focused regression coverage; all 46 selected tests pass.
- [x] Localization: No new user-facing strings; normalization and existing localized search behavior are unchanged.
Issue closure, development/user documentation, and new-binary checklist items are N/A. No new projects, dependencies, binaries, or persisted settings changes.
Detailed Description of the Pull Request / Additional comments
Trigger: A query consisting of U+00A8 (spacing diaeresis) passes the initial whitespace check in src\settings-ui\Settings.UI\Services\SearchIndexService.cs. FormKD normalization decomposes it into U+0020 plus a combining mark; removing nonspacing marks leaves a single space. Previously, src\common\Common.Search\FuzzSearch\StringMatcher.cs checked only for null/empty input before trimming, then indexed the first element of an empty token array. With a populated search index, the resulting IndexOutOfRangeException can propagate through Parallel.ForEach to the live search handler, which catches cancellation only. This is a source/unit-test finding, not a claim of a reproduced live application crash.
The Settings service now returns no results after normalization when no searchable text remains. The shared matcher rejects null/empty/whitespace queries before its per-start-index matching loop, preventing empty trimmed/tokenized input from reaching the indexed access. Both use existing no-match behavior rather than adding an exception catch.
Shared-caller risk: Common.Search is also used by Shortcut Guide and the Command Palette PowerToys extension. Their existing blank-query handling remains unchanged, as do the matching algorithm, separators, scoring, highlighting, and case options for nonempty queries. No public API signature changes. NormalizeString becomes internal solely for direct coverage through the existing Settings test friend assembly.
Tests are in the existing src\settings-ui\Settings.UI.UnitTests\Search\StringMatcherTests.cs and src\settings-ui\Settings.UI.UnitTests\Search\SearchIndexServiceTests.cs; there is no standalone Common.Search test project on current main. The service fixture supplies a nonempty in-memory index, restores it afterward, and does not load Settings resources or change user settings.
This PR deliberately excludes expander-result filtering and prebuilt search-index generation/embedding changes. It does not auto-close the different search-crash reports #41817 or #47118.
Validation Steps Performed
- Ran the repository first-build prerequisite
tools\build\build-essentials.cmd -Platform x64 -Configuration Releaseafter the fresh worktree reported missing NuGet assets; restore and essentials completed successfully. - Built
Settings.UI.UnitTestsin Release x64 usingtools\build\build.ps1with the worktreeSolutionDir; exit code 0. - Ran the existing Microsoft.Testing.Platform runner with
--filter "FullyQualifiedName~Settings.UI.UnitTests.Search" --minimum-expected-tests 46 --report-trx: 46 passed, 0 failed, 0 skipped. - Covered null/empty/ASCII whitespace, Unicode spaces, U+00A8 compatibility normalization, combining-only queries, both Search overloads with a nonempty index, both case options, ordinary/padded/multiword queries, unchanged scores/highlights, exact-match ranking, and accented/fullwidth normalization.
- Did not launch or modify the installed/running PowerToys instance or user settings.