[Server] Restore CurrentCulture/CurrentUICulture at end of each request#13756
[Server] Restore CurrentCulture/CurrentUICulture at end of each request#13756JanProvaznik wants to merge 1 commit into
Conversation
Snapshot Thread.CurrentThread.CurrentCulture and CurrentUICulture once at server startup (in OutOfProcServerNode.Run, before the listener loop begins), then restore them in a try/finally around each HandleServerNodeBuildCommand invocation. Without this, each request mutates the server thread's culture from command.Culture and command.UICulture but never reverts. A subsequent request whose client provides identical cultures sees no observable problem, but if the server enters a state-read code path between requests (lazy initializers, finalizers, GC callbacks reading CultureInfo.CurrentCulture), it sees the prior request's culture rather than the server's process-startup baseline. Symmetric snapshot/restore matches the existing working-directory restore pattern in HandleShutdown. Investigation context: investigation.md Thread G item 3 in the broader MSBuild Server default-on analysis (dotnet#9379). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
iterated that this is not a realistic failure mode, not worth fixing, but I'm glad the investigation was done |
|
Closing rationale (post-review): this PR fixes a leak that only a contract-violating task or logger could cause. MSBuild tasks aren't supposed to touch I was building justification for a fix in search of a problem. Confirming the close was correct; same logic applied to #13757 which I just closed. The other two server PRs from the same investigation stand on their own merits:
See #9379 for the consolidated default-on analysis. |
Server: Restore
CurrentCulture/CurrentUICultureat end of each requestSnapshot
Thread.CurrentThread.CurrentCultureandCurrentUICultureonce at server startup (inOutOfProcServerNode.Run, before the listener loop), then restore them in atry/finallyaround eachHandleServerNodeBuildCommandinvocation.Why the failure mode is weak
Each request explicitly sets
Thread.CurrentThread.CurrentCulture = command.Culture(OutOfProcServerNode.cs:386-387) before any culture-sensitive build work runs. Build work runs synchronously on the sameTask.Run-spawned ThreadPool thread, so the per-request set covers the whole request. Walking the lifecycle:Task.Runpicks a ThreadPool thread → sets culture to N's → build runs → returns.Task.Runpicks some ThreadPool thread (maybe the same one) → sets culture to N+1's → build runs.Whichever thread N+1's
Task.Runpicks, the very first thing it does is overwrite the culture. So the prior request's culture cannot leak into N+1's build. The narrow scenarios where the leftover culture could matter are all weak:CurrentCulturefor trace formattingcommand.Cultureset, so it uses the process default — unaffected by this PRCurrentCultureThread.CurrentThread.CurrentCulturefor use laterWhat the test actually proves (and doesn't)
MSBuildServer_Tests.ServerBuildsUseCultureFromEachRequestruns back-to-back en-US then fr-FR builds and asserts each build's task observes its own culture and that the server PID is reused. The test passes with or without the restore code in this PR, because the explicit set inHandleServerNodeBuildCommandalready guarantees correctness for what the test observes.So the test is a useful regression for the existing per-request set behavior, but it does NOT validate that this PR fixes any concrete bug.
Why merge anyway (defense-in-depth case)
HandleShutdownalready resets the working directory; CWD restore was added for the same "between-requests cleanliness" reason. This PR extends that pattern to culture.What this PR is NOT
It is not a fix for:
TimeoutException(that's Fix TimeoutException when DOTNET_CLI_USE_MSBUILD_SERVER=true on .NET 10.0.300 #13716 + the prototype's M1)Implementation
_originalCulture/_originalUICultureinRun()before the listener loop.HandleServerNodeBuildCommandin atry/finallythat restores both.OutOfProcServerNode.cs(+19 lines),MSBuildServer_Tests.cs(+86 lines for the regression test + helper task).Recommendation
Merge if the maintainers value defense-in-depth hygiene + symmetry with the existing CWD reset; close as "premature optimization" if not. I have no strong preference but lean toward merge given the very low cost.
Investigation context: #9379 Thread G item 3.