LegendaryBlair's Description of Work
Summary of the Pull Request
Disable Hybrid CRT by default as a scoped rollback of the build-policy change in #50899, mitigating Runner exit hangs involving the shared UCRT exit-table lock.
Cpp.Build.props now defaults EnableHybridCRT to false when no value is supplied. Native projects return to private static UCRT linkage, while explicit opt-ins and independent project-level Hybrid CRT linker settings remain supported.
The New+ locale/environment-variable changes and the logger environment-variable fix from #50899 are intentionally retained. Only Cpp.Build.props and the directly related runtime guidance in doc/devdocs/development/guidelines.md change.
PR Checklist
- [ ] Closes: N/A (partial rollback of #50899; no separate issue linked)
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] Communication: I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected
- [ ] Tests: Added/updated and all pass. No new application unit tests; native build and effective-linkage validation are listed below.
- [x] Localization: All end-user-facing strings can be localized (N/A: no user-facing strings)
- [x] Dev docs: Added/updated
- [ ] New binaries: Added on the required places (N/A: no new binaries)
- [ ] JSON for signing for new binaries
- [ ] WXS for installer for new binaries and localization folder
- [ ] YML for CI pipeline for new test projects
- [ ] YML for signed pipeline
- [ ] Documentation updated: If checked, please file a pull request on our docs repo and link it here: N/A (developer guidance is updated in this PR; no user documentation changes)
Detailed Description of the Pull Request / Additional comments
Why restore private UCRT linkage?
Matching-symbol inspection of installed 0.102.2883.0 found Runner performing static module destruction inside ucrtbase!execute_onexit_table. In one confirmed wait cycle:
- The Runner main thread holds the CRT exit-table lock and joins the PowerDisplay executor while destroying the module.
- The executor creates an ATL
CStringwhile sending the shutdown message. Lazy static initialization callsatexit/register_onexit_function, which needs the same shared CRT lock.
Other captured remnants show related exit-table/loader waits involving Light Switch listener cleanup and Mouse Highlighter DLL detach. Sharing the UCRT makes these previously separate runtime locks shared across the executable and module DLLs.
The reported working/failing boundary is 0.101.2362.0 to 0.102.2803.0. Git ancestry confirms that the latter includes #50899 but does not yet include #50897 or #51115. This is a build-policy mitigation, not a rewrite of Runner shutdown sequencing.
Scope and tradeoffs
- Preserve
/MTand/MTd; disable the defaultlibucrtexclusion and shared-UCRT import-library selection by making their existing condition false. - Preserve
CalculatorEngineCommon's explicit opt-in, the Command Palette Extensions SDK's independent Hybrid CRT linker configuration, and existing project opt-outs. - No CI/workflow/build-script override re-enables Hybrid CRT for Runner or its affected native modules.
- Preserve the New+ and logger fixes, settings/IPC formats, and installed-user state.
- Accept losing the default binary-size reduction until shutdown lifetimes are made safe for a shared CRT. No current installer-size measurement is claimed.
Validation Steps Performed
Native builds: passed
The following commands were run in the isolated worktree. All completed with exit code 0 after restoring the fresh worktree's missing native packages.
# PASS: native package restore.
& 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'D:\PowerToys-hybrid-crt-rollback\tools\build\build.ps1' -Platform x64 -Configuration Release -Path 'D:\PowerToys-hybrid-crt-rollback\src\modules\powerdisplay\PowerDisplayModuleInterface' '/t:Restore' '/p:RestorePackagesConfig=true' '/p:SolutionDir=D:\PowerToys-hybrid-crt-rollback\' '/p:SkipLongPathsCheck=true'
# PASS: PowerDisplayModuleInterface and native dependencies; 0 errors, 0 warnings.
& 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'D:\PowerToys-hybrid-crt-rollback\tools\build\build.ps1' -Platform x64 -Configuration Release -Path 'D:\PowerToys-hybrid-crt-rollback\src\modules\powerdisplay\PowerDisplayModuleInterface' '/p:SolutionDir=D:\PowerToys-hybrid-crt-rollback\' '/p:SkipLongPathsCheck=true'
# PASS: Runner and native dependencies; 0 errors, 1 host LIB-path warning.
& 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'D:\PowerToys-hybrid-crt-rollback\tools\build\build.ps1' -Platform x64 -Configuration Release -Path 'D:\PowerToys-hybrid-crt-rollback\src\runner' '/restore' '/p:RestorePackagesConfig=true' '/p:SolutionDir=D:\PowerToys-hybrid-crt-rollback\' '/p:SkipLongPathsCheck=true'
The host has Windows long-path support disabled; the repository's documented SkipLongPathsCheck override was used for these scoped native builds without changing machine policy. Runner's warning was CS1668 for a nonexistent Visual Studio LIB search directory, not a source warning introduced by this change.
Effective compiler/linker configuration: 25 cases passed
A local-only MSBuild diagnostic target imported the original Cpp.Build.targets, added a non-built Link probe item to obtain evaluated item-definition metadata, and returned EnableHybridCRT, the actual ClCompile.RuntimeLibrary values, Link.IgnoreSpecificDefaultLibraries, and Link.AdditionalOptions.
For each project/configuration/platform row, the command was:
# PASS for all 24 matrix rows; $probe is the local ReportCrtLinkage.targets file.
& $msbuild $project /nologo /v:q /t:ReportCrtLinkage /getTargetResult:ReportCrtLinkage "/p:Platform=$platform" "/p:Configuration=$configuration" '/p:SolutionDir=D:\PowerToys-hybrid-crt-rollback\' "/p:ForceImportAfterCppTargets=$probe" /p:SkipLongPathsCheck=true
# PASS: additional Runner x64 Release positive control, using the same command with:
# /p:EnableHybridCRT=true
Projects
Configurations
Platforms
Result
Runner, PowerDisplayModuleInterface, LightSwitchModuleInterface, MouseHighlighter
Debug, Release
x64, ARM64
Private UCRT; /MTd or /MT; no shared-UCRT linker overrides
CalculatorEngineCommon
Debug, Release
x64, ARM64
Explicit Hybrid CRT opt-in retained
Command Palette Extensions SDK
Debug, Release
x64, ARM64
Independent Hybrid CRT linker configuration retained
Runner with explicit EnableHybridCRT=true
Release
x64
Opt-in still selects the shared UCRT
The four affected native projects and the positive control were evaluated with VS 2026 MSBuild. The two unchanged UWP opt-in projects were evaluated with installed VS 2022 MSBuild because the VS 2026 Build Tools installation lacks the UWP XAML targets. These are configuration evaluations, not ARM64 build/runtime passes.
Rebuilt binary imports: passed
# PASS: both dumpbin commands exited 0.
& $dumpbin /nologo /imports 'D:\PowerToys-hybrid-crt-rollback\x64\Release\PowerToys.exe'
& $dumpbin /nologo /imports 'D:\PowerToys-hybrid-crt-rollback\x64\Release\PowerToys.PowerDisplayModuleInterface.dll'
Both rebuilt binaries have no api-ms-win-crt-*, ucrtbase.dll, or ucrtbased.dll imports. This checks the resulting linkage, not only the property value.
git diff --check also passed.
Not claimed: application unit/UI test execution, a full installer or ARM64 build, or a post-change installed-product shutdown/restart A/B. The installed PowerToys binaries and existing hung-process evidence were not replaced or terminated.