dotnet / dotnet/runtime

There is an inconsistency in behavior between `string.Format(IFormatProvider?, string, *)` and `string.Format(IFormatProvider?, CompositeFormat, *)`.

Open
#119,756 3 comments 0 reactions 0 assignees View on GitHub
area-System.Runtime help wanted
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Description

`StringBuilder` and `ValueStringBuilder` impose limits on `Index` and `Width`, but `CompositeFormat.Parse` does not, resulting in inconsistent behavior. Since `CompositeFormat.Parse` also triggers a CA2241 warning, this creates a discrepancy with the analyzer as well.

https://github.com/dotnet/runtime/blob/54a230fd9fe18ab14be1f629566be1e87a3f88e4/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs#L1523-L1525
https://github.com/dotnet/runtime/blob/54a230fd9fe18ab14be1f629566be1e87a3f88e4/src/libraries/System.Private.CoreLib/src/System/Text/ValueStringBuilder.AppendFormat.cs#L18-L20

https://github.com/dotnet/runtime/blob/54a230fd9fe18ab14be1f629566be1e87a3f88e4/src/libraries/System.Private.CoreLib/src/System/Text/CompositeFormat.cs#L112

### Reproduction Steps

```csharp
var numbers = Enumerable.Range(0, 100000000).Cast().ToArray();

Run("Index= 9999999:CompositeFormat", () => string.Format(null, CompositeFormat.Parse("{9999999}"), numbers).Length);
Run("Index=10000000:CompositeFormat", () => string.Format(null, CompositeFormat.Parse("{10000000}"), numbers).Length);
Run("Index= 9999999:string ", () => string.Format(null, "{9999999}", numbers).Length);
Run("Index=10000000:string ", () => string.Format(null, "{10000000}", numbers).Length);

Console.WriteLine();

Run("Width= 9999999:CompositeFormat", () => string.Format(null, CompositeFormat.Parse("{0,9999999}"), "format").Length);
Run("Width=10000000:CompositeFormat", () => string.Format(null, CompositeFormat.Parse("{0,10000000}"), "format").Length);
Run("Width= 9999999:string ", () => string.Format(null, "{0,9999999}", "format").Length);
Run("Width=10000000:string ", () => string.Format(null, "{0,10000000}", "format").Length);

void Run(string name, Func func)
{
try
{
Console.WriteLine($"{name}: {func()}");
}
catch (Exception e)
{
Console.WriteLine($"{name}: {e.GetType()}: {e.Message}");
}
}
```

### Expected behavior

```
Index= 9999999:CompositeFormat: 7
Index=10000000:CompositeFormat: System.FormatException: Input string was not in a correct format. Failure to parse near offset 10. Format item ends prematurely.
Index= 9999999:string : 7
Index=10000000:string : System.FormatException: Input string was not in a correct format. Failure to parse near offset 8. Format item ends prematurely.

Width= 9999999:CompositeFormat: 9999999
Width=10000000:CompositeFormat: System.FormatException: Input string was not in a correct format. Failure to parse near offset 10. Format item ends prematurely.
Width= 9999999:string : 9999999
Width=10000000:string : System.FormatException: Input string was not in a correct format. Failure to parse near offset 10. Format item ends prematurely.
```

### Actual behavior

```
Index= 9999999:CompositeFormat: 7
Index=10000000:CompositeFormat: 8
Index= 9999999:string : 7
Index=10000000:string : System.FormatException: Input string was not in a correct format. Failure to parse near offset 8. Format item ends prematurely.

Width= 9999999:CompositeFormat: 9999999
Width=10000000:CompositeFormat: 10000000
Width= 9999999:string : 9999999
Width=10000000:string : System.FormatException: Input string was not in a correct format. Failure to parse near offset 10. Format item ends prematurely.
```

### Regression?

_No response_

### Known Workarounds

_No response_

### Configuration

.NET 8 or later

### Other information

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.