Uh oh!
There was an error while loading. Please reload this page.
Reject "root" culture name in ICU globalization mode - #133275
Open
tarekgh wants to merge 1 commit into
Open
Conversation
CultureInfo.GetCultureInfo("root") was accepted in ICU mode but produced an
incomplete culture. ICU normalizes the CLDR "root" locale to an empty name, so
the resulting CultureData had Name == "" without being the Invariant singleton.
That caused a NullReferenceException when reading NumberFormat and poisoned the
invariant culture's "" cache slot when "root" was resolved before the invariant
culture.
The empty-string and "und" names are already short-circuited to the invariant
culture in GetCultureData, so an empty name in InitIcuCultureDataCore can only
come from a name such as "root" that is not a valid culture. Reject it so
GetCultureInfo("root") throws CultureNotFoundException, matching the existing
NLS behavior.
Fixesdotnet#132429|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
Tagging subscribers to this area: @dotnet/area-system-globalization |
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The change is a narrowly-scoped correctness fix on a cold path with targeted regression tests validating both the exception behavior and the cache-poisoning scenario.
Pull request overview
This PR fixes an ICU-mode globalization edge case where CultureInfo.GetCultureInfo("root") could succeed but produce a broken culture (with Name == ""), leading to internal NullReferenceExceptions and poisoning the CultureInfo name cache entry for the invariant culture.
Changes:
- Reject ICU-normalized empty locale names during ICU culture initialization to ensure
"root"fails culture creation rather than producing an incomplete culture. - Add regression coverage ensuring
"root"throwsCultureNotFoundExceptionacross key entry points and does not poison the invariant culture cache (including verifying"und"still maps to invariant). - Gate the tests to only run when a non-invariant globalization backend is in use and RemoteExecutor is available.
File summaries
| File | Description |
|---|---|
| src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Icu.cs | Adds a guard to fail ICU culture initialization if ICU returns an empty locale name (preventing "root" from creating a broken culture and avoiding cache poisoning). |
| src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/GetCultureInfo.cs | Adds regression tests verifying "root" throws and does not poison the invariant culture cache (and that "und" still maps to invariant). |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 0
- Review effort level: Lite
This was referenced Sep 5, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes#132429.
CultureInfo.GetCultureInfo("root")was accepted in ICU globalization mode but produced an incomplete culture. ICU normalizes the CLDRrootlocale to an empty name, so the resultingCultureDatahadName == ""without being theInvariantsingleton. This caused two problems:NumberFormaton it threwNullReferenceExceptionfromNumberFormatInfo.InitializeInvariantAndNegativeSignFlagsbecause the negative sign was never populated."root"before the invariant culture poisoned the""cache slot, so later lookups of the invariant culture returned the broken instance.Fix
The empty-string and
"und"names are already short-circuited to the invariant culture inCultureData.GetCultureData, so an empty name reachingInitIcuCultureDataCorecan only come from a name such as"root"that is not a valid culture. The change rejects that case, soGetCultureInfo("root")now throwsCultureNotFoundException, matching the existing NLS behavior (Windows does not recognizeroot).This is a single length check on the culture creation cold path (cache miss only), so there is no impact on the hot path or on any valid culture.
Behavior by globalization mode
NumberFormat, cache poisoningCultureNotFoundExceptionCultureNotFoundExceptionCultureNotFoundExceptionrootfrom invariant dataTests
Added to
System.Globalization.Tests.GetCultureInfoTests(gated onIsNotInvariantGlobalization):GetCultureInfo_RootCultureName_Throwsforroot,ROOT,Rootacross all overloads and theCultureInfoconstructor.GetCultureInfo_RootCultureName_DoesNotPoisonInvariantCacheusing RemoteExecutor to verify that resolvingrootfirst leaves the invariant culture intact and thatundstill maps to invariant.Verified locally on Windows x64 (ICU): the full
GetCultureInfoTestsclass passes (65/65) with the fix, and the new tests fail without it.