Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 17, 2025

Fix culture-sensitive numeric formatting in compiler-generated strings

Issue: When compiling under non-US cultures (e.g., Swedish sv-SE), the compiler uses culture-specific number formatting when appending numeric values to strings. This causes issues like:

  • Interpolated strings with negative alignment values (e.g., $"{st,-100}") generate invalid format strings with culture-specific minus signs ( U+2212 instead of - U+002D), leading to runtime FormatException
  • Documentation comment IDs, assembly identity strings, generated names, and other compiler-generated strings contain culture-specific number formatting

Root Cause: Throughout the codebase, stringBuilder.Append with numeric values and parameterless ToString() methods were used, which use the current culture's formatting rules.

Solution: Modified the code to use ToString(System.Globalization.CultureInfo.InvariantCulture) for all numeric StringBuilder.Append and ToString operations to ensure values are always formatted with standard ASCII characters, regardless of the compilation culture.

Changes:

  • Core Compiler (src/Compilers/Core/Portable/) - 12 files:

    • DocumentationCommentId.cs: Fixed TypeParameters.Length and Ordinal appends (5 instances)
    • AssemblyIdentity.DisplayName.cs: Fixed version number appends (Major, Minor, Build, Revision)
    • Syntax/LineMapping.cs: Fixed CharacterOffset append
    • BannedSymbols.CompilerLibraries.txt: Added 23 banned symbol entries to prevent future regressions
    • InternalUtilities/StringExtensions.cs: Fixed numeric ToString
    • CodeGen/PrivateImplementationDetails.cs: Fixed submissionSlotIndex and analysisIndex ToString (2 instances)
    • CodeGen/LocalOrParameter.cs: Fixed ParameterIndex ToString
    • CodeGen/DebugId.cs: Fixed Ordinal ToString
    • PEWriter/MetadataWriter.PortablePdb.cs: Fixed CompilationOptionsVersion, SourceFileCount, and PortabilityPolicy ToString (3 instances)
    • ExtendedSpecialType.cs: Fixed _value ToString
    • DiagnosticAnalyzer/ShadowCopyAnalyzerPathResolver.cs: Fixed _directoryCount ToString
    • MetadataReader/MetadataTypeName.cs: Fixed _forcedArity ToString
  • C# Compiler (src/Compilers/CSharp/Portable/) - 5 files:

    • Binder/Binder_InterpolatedString.cs: Fixed nextFormatPosition and alignment value appends
    • DocumentationComments/DocumentationCommentIDVisitor.PartVisitor.cs: Fixed Arity and Ordinal appends (3 instances)
    • Symbols/SymbolCompletionState.cs: Fixed completion part index append
    • Symbols/Synthesized/GeneratedNames.cs: Fixed methodOrdinal, entityOrdinal, generation, slotIndex, ownerUniqueId, and id appends (7 instances)
    • Symbols/Synthesized/SynthesizedLocal.cs: Fixed sequence and createdAtLineNumber appends (3 instances)
  • VB Compiler (src/Compilers/VisualBasic/Portable/) - 11 files:

    • Binding/Binder_InterpolatedString.vb: Already had InvariantCulture in place (verified)
    • DocumentationComments/DocumentationCommentIDVisitor.PartVisitor.vb: Fixed Arity and Ordinal appends (3 instances)
    • Symbols/SynthesizedSymbols/GeneratedNames.vb: Fixed methodOrdinal, entityOrdinal, and generation appends (4 instances)
    • Binding/Binder_AnonymousTypes.vb: Fixed fieldIndex ToString
    • Binding/Binder_Query.vb: Fixed i ToString in anonymous field name
    • CodeGen/EmitStatement.vb: Fixed cur ToString in case block label
    • CodeGen/Optimizer/StackScheduler.LocalDefUseSpan.vb: Fixed Start and End ToString (2 instances)
    • Errors/DiagnosticFormatter.vb: Fixed line number ToString
    • SymbolDisplay/ObjectDisplay.vb: Fixed codepoint ToString (2 instances)
    • SymbolDisplay/SymbolDisplayVisitor.Types.vb: Fixed Arity ToString
    • Symbols/Attributes/AttributeData.vb: Fixed value ToString
    • Symbols/Source/RangeVariableSymbol.vb: Fixed _syntax.Position ToString
  • Dependencies (src/Dependencies/) - 2 files:

    • Contracts/Index.cs: Fixed Value ToString (2 instances)
    • Contracts/Range.cs: Fixed Value ToString
  • Workspace Files (src/Workspaces/) - 4 files:

    • Remote/ServiceHub/Services/DiagnosticAnalyzer/PerformanceTrackerService.cs: Fixed unitCount, BuiltIn, and TotalMilliseconds appends
    • Core/Portable/Log/HistogramLogAggregator.cs: Fixed bucket value appends
    • Core/Portable/Log/RoslynEventSource.cs: Fixed enum value append
    • Remote/Core/ExportProviderBuilder.cs: Fixed Version.Major append
  • Test Infrastructure (src/Compilers/Test/) - 9 files:

    • CSharp/Test/Emit3/Diagnostics/OperationAnalyzerTests.cs: Fixed test code generation
    • CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs: Fixed test code generation
    • CSharp/Test/Emit/CodeGen/CodeGenOperators.cs: Fixed test code generation (9 instances)
    • CSharp/Test/EndToEnd/EndToEndTests.cs: Fixed test code generation
    • CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs: Fixed test code generation
    • Test/Core/Diagnostics/DiagnosticDescription.cs: Fixed line and character position appends
    • Test/Core/Platform/Desktop/CLRHelpers.cs: Fixed format string index append
    • Test/Utilities/VisualBasic/ParserTestUtilities.vb: Fixed error ID append
    • VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb: Fixed test code generation (6 instances)
  • Editor Features (src/EditorFeatures/) - 1 file:

    • Test2/Classification/SyntacticChangeRangeComputerTests.vb: Fixed test code generation
  • Visual Studio Integration (src/VisualStudio/) - 1 file:

    • Core/Impl/CodeModel/MetadataNameHelpers.cs: Fixed TypeArguments.Length append

Testing:

  • C# Test (CodeGenInterpolatedString.cs):

    • Converted test to use raw string literals
    • Added CultureContext to explicitly test compilation under Swedish culture (sv-SE)
    • Verifies code compiles and runs correctly with both positive and negative alignment values
    • Validates emitted IL contains correct format strings (e.g., {0,-100}) even when compiled under sv-SE culture
  • VB Test (InterpolatedStringTests.vb):

    • Added parallel test using WriteLine to verify VB compiler behavior under Swedish culture
    • Validates emitted IL contains correct format strings with negative alignment
  • All existing tests continue to pass for both C# and VB compilers

  • Build with analyzers (./build.sh --runAnalyzers) passes with no RS0030 violations

Prevention of Future Regressions:

Added 23 entries to BannedSymbols.CompilerLibraries.txt to prevent reintroduction of culture-sensitive formatting issues:

  • Banned all numeric StringBuilder.Append() overloads (SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal)
  • Banned parameterless ToString() methods for all numeric types
  • Build errors will guide developers to use ToString(CultureInfo.InvariantCulture) instead

Files Modified: 44 files total across:

  • Compiler core (19 files including banned symbols)
  • Tests (10 files)
  • Workspaces (4 files)
  • Visual Studio integration (1 file)
  • Dependencies (2 files)

This comprehensive fix ensures all parts of the compiler, test infrastructure, workspace services, and related tools generate consistent, culture-independent output regardless of the system culture during compilation or testing. The banned symbols list prevents future regressions by failing the build if culture-sensitive APIs are used.

Fixes #49826

Original prompt

This section details on the original issue you should resolve

<issue_title>FormatException on right padding a interpolated string</issue_title>
<issue_description>

Description

Right padding a string with interpolated strings throw a System.FormatException

Code to reproduce:

using System;

namespace tmp5
{
    class Program
    {
        static void Main(string[] args)
        {
            var st = "1";
            var st2 = $"{st,100}";  // Ok
            var st3 = $"{st,-100}"; // FormatException here
        }
    }
}

Configuration

Bug reproduced with net5.0 and netcore3.0 build target.

dotnet --info
.NET SDK (reflecting any global.json):
Version: 5.0.100
Commit: 5044b93829

Runtime Environment:
OS Name: ubuntu
OS Version: 18.04
OS Platform: Linux
RID: ubuntu.18.04-x64
Base Path: /usr/share/dotnet/sdk/5.0.100/

Host (useful for support):
Version: 5.0.0
Commit: cf258a14b7

.NET SDKs installed:
3.1.404 [/usr/share/dotnet/sdk]
5.0.100 [/usr/share/dotnet/sdk]

.NET runtimes installed:
Microsoft.AspNetCore.App 3.1.10 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.0 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.10 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.0 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

Operating System: Feren OS 2020.07
KDE Plasma Version: 5.19.4
KDE Frameworks Version: 5.72.0
Qt Version: 5.14.2
Kernel Version: 5.4.0-56-generic
OS Type: 64-bit
Processors: 16 × AMD Ryzen 7 3700X 8-Core Processor
Memory: 31,4 GiB of RAM
Graphics Processor: AMD Radeon RX 5700

Regression?

Found this when porting a project from .net framework 4.6.

Other information

I have found no workarounds.</issue_description>

<agent_instructions>Copilot, it looks like we're appending a value in a culture sensitive fashion, instead of in an invariant fashion. Can you fix the offending line stringBuilder.Append(',').Append(fillin.Alignment.ConstantValueOpt.Int64Value);

We'll likely need a test that come somehow verify the emitted IL under a non en-US culture. Not sure if the compiler test harness makes that possible or not.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@Dotnet-GitSync-Bot I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one [area label](https://github.com/dotnet/runtime/blob/master/docs/area-owners.md). @stephentoub I tried this on both .NET Core 3.1 and .NET 5, on both Windows and Ubuntu, and I could not repro a FormatException. @stephentoub What is your CultureInfo.CurrentCulture? @stephentoub I'm guessing this is due to the CLDR defining the minus sign as `−` rather than `-` for sv-SE: https://github.com/dotnet/runtime/issues/44678#issuecomment-727261177 @Dotnet-GitSync-Bot I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one [area label](https://github.com/dotnet/runtime/blob/master/docs/area-owners.md). @ Tagging subscribers to this area: @tarekgh, @safern, @krwq See info in area-owners.md if you want to be subscribed.
Issue Details

Description

Right padding a string with interpolated strings throw a System.FormatException

Code to reproduce:

using System;

namespace tmp5
{
    class Program
    {
        static void Main(string[] args)
        {
            var st = "1";
            var st2 = $"{st,100}";  // Ok
            var st3 = $"{st,-100}"; // FormatException here
        }
    }
}

Configuration

Bug reproduced with net5.0 and netcore3.0 build target.

dotnet --info
.NET SDK (reflecting any global.json):
Version: 5.0.100
Commit: 5044b93829

Runtime Environment:
OS Name: ubuntu
OS Version: 18.04
OS Platform: Linux
RID: ubuntu.18.04-x64
Base Path: /usr/share/dotnet/sdk/5.0.100/

Host (useful for support):
Version: 5.0.0
Commit: cf258a14b7

.NET SDKs installed:
3.1.404 [/usr/share/dotnet/sdk]
5.0.100 [/usr/share/dotnet/sdk]

.NET runtimes installed:
Microsoft.AspNetCore.App 3.1.10 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.0 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.10 [/usr/share/dotnet/shared/Microsoft....

Fixes #49826


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix FormatException on right padding with interpolated strings Fix FormatException when compiling interpolated strings with negative alignment under non-US cultures Oct 17, 2025
Copilot AI requested a review from CyrusNajmabadi October 17, 2025 14:41
Copilot finished work on behalf of CyrusNajmabadi October 17, 2025 14:41
// This test verifies that negative alignment values are formatted using invariant culture.
// The issue occurs when compiling under non-US cultures (e.g., Swedish sv-SE) where the
// minus sign is formatted as '−' (U+2212) instead of '-' (U+002D), causing runtime errors.
var source = @"
Copy link
Member

Choose a reason for hiding this comment

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

@copilot use raw string literals for tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Converted to raw string literals in commit b0a5c12.

}
}
";
var comp = CompileAndVerify(source, expectedOutput: @" 1
Copy link
Member

Choose a reason for hiding this comment

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

@copilot is tehre some way to set teh culture for the compiler for a particular test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added CultureContext to explicitly test compilation under Swedish culture (sv-SE) in commit b0a5c12. The test now wraps the compilation in using (new CultureContext(new CultureInfo("sv-SE", useUserOverride: false))) to verify the fix works correctly even when the compiler runs under a culture where minus signs are formatted differently.

…ng alignment test

Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
Copilot AI requested a review from CyrusNajmabadi October 17, 2025 15:18
Copilot finished work on behalf of CyrusNajmabadi October 17, 2025 15:18
@CyrusNajmabadi CyrusNajmabadi marked this pull request as ready for review October 17, 2025 16:31
@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner October 17, 2025 16:31
Co-authored-by: AlekseyTs <10522107+AlekseyTs@users.noreply.github.com>
Copilot AI changed the title Fix FormatException when compiling interpolated strings with negative alignment under non-US cultures Fix FormatException when compiling interpolated strings with numeric values under non-US cultures Oct 17, 2025
Copilot finished work on behalf of AlekseyTs October 17, 2025 19:16
Copilot AI requested a review from AlekseyTs October 17, 2025 19:16
@AlekseyTs
Copy link
Contributor

Done with review pass (commit 3)

Copilot finished work on behalf of AlekseyTs October 17, 2025 19:52
}

[Fact, WorkItem("https://github.com/dotnet/runtime/issues/44678")]
public void AlignmentWithNegativeValue()
Copy link
Contributor

Choose a reason for hiding this comment

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

@copilot Please add similar test for VB compiler

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added VB test in commit 4f8e7a9. The test verifies that negative alignment values compile correctly under Swedish culture (sv-SE) and validates the emitted IL contains the proper format string {0,-100}.

…lues

Co-authored-by: AlekseyTs <10522107+AlekseyTs@users.noreply.github.com>
Copilot AI requested a review from AlekseyTs October 17, 2025 20:06
Copilot finished work on behalf of AlekseyTs October 17, 2025 20:06
@AlekseyTs
Copy link
Contributor

Done with review pass (commit 9)

@AlekseyTs AlekseyTs changed the title Fix culture-sensitive StringBuilder.Append calls across compiler codebase Copilot: Fix culture-sensitive StringBuilder.Append calls across codebase Oct 19, 2025
Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM (commit 9)

@AlekseyTs
Copy link
Contributor

@CyrusNajmabadi Please review

@AlekseyTs
Copy link
Contributor

@dotnet/roslyn-compiler For a second review

@AlekseyTs AlekseyTs requested a review from a team October 19, 2025 01:16
Copy link
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

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

Can we add the bad ToString apis to src/Compilers/Core/Portable/BannedSymbols.CompilerLibraries.txt, so we don't accidentally reintroduce this problem?

Copy link
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

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

Signing off on the non-Compiler changes.

@CyrusNajmabadi
Copy link
Member

@copilot Can you add the bad ToString/Append apis to src/Compilers/Core/Portable/BannedSymbols.CompilerLibraries.txt

…nned symbols

Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Oct 21, 2025

@copilot Can you add the bad ToString/Append apis to src/Compilers/Core/Portable/BannedSymbols.CompilerLibraries.txt

Added in commit a7f9c2e. Banned all culture-sensitive numeric ToString() overloads (parameterless versions for SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal) and their corresponding StringBuilder.Append() overloads. These methods will now trigger build errors if used in compiler code, directing developers to use ToString(CultureInfo.InvariantCulture) instead.

Copilot AI changed the title Copilot: Fix culture-sensitive StringBuilder.Append calls across codebase Copilot: Fix culture-sensitive StringBuilder.Append calls across codebase and add banned symbols Oct 21, 2025
Copilot finished work on behalf of CyrusNajmabadi October 21, 2025 10:46
@333fred
Copy link
Member

333fred commented Oct 24, 2025

@copilot the bans caught a few more locations that are using the banned apis; run a build locally using ./build.sh --runAnalyzers and fix them up.

… symbols

Co-authored-by: 333fred <2371880+333fred@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Oct 24, 2025

@copilot the bans caught a few more locations that are using the banned apis; run a build locally using ./build.sh --runAnalyzers and fix them up.

Fixed in commit e4a8f9b. Applied InvariantCulture to all additional ToString() violations caught by the banned symbols across 22 more files (10 C# compiler files, 10 VB compiler files, and 2 dependency files). Build with ./build.sh --runAnalyzers now passes with no RS0030 violations.

Copilot AI changed the title Copilot: Fix culture-sensitive StringBuilder.Append calls across codebase and add banned symbols Copilot: Fix culture-sensitive StringBuilder.Append and ToString calls across codebase and add banned symbols Oct 24, 2025
Copilot AI requested a review from 333fred October 24, 2025 18:26
Copilot finished work on behalf of 333fred October 24, 2025 18:26
@CyrusNajmabadi CyrusNajmabadi enabled auto-merge (squash) October 24, 2025 22:25
@CyrusNajmabadi CyrusNajmabadi merged commit 5ce2f56 into main Oct 24, 2025
27 of 28 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Oct 24, 2025
@CyrusNajmabadi CyrusNajmabadi deleted the copilot/fix-format-exception-padding branch October 25, 2025 01:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FormatException on right padding a interpolated string

5 participants