You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
$"{x}" / StringBuilder.Append(x) never returns for a value with an extreme exponent: TryFormat returns false where ToString throws OverflowException #144
For a value whose fixed-point text would be longer than any string can hold (more than Array.MaxLength characters), ToString() checks the required length (PreciseNumber/PreciseNumber.cs:~503-513) and throws OverflowException. TryFormat (PreciseNumber.cs:1354 onwards) has no such check. It just returns false when the text doesn't fit.
ISpanFormattable callers read false as "the destination was too small". DefaultInterpolatedStringHandler (every $"..."), StringBuilder.Append(ISpanFormattable), string.Format and others respond by growing the buffer and calling again. No buffer can ever be large enough, so they grow until an allocation fails or loop indefinitely.
Reproduction
varx=PreciseNumber.Parse("1e-2147483648",CultureInfo.InvariantCulture);x.ToString();// OverflowException after ~4 ms_=$"{x}";// still running when killed after a 120 s timeout
Why it matters
The PR #77 fix for #75 deliberately changed TryFormat to return false here instead of throwing. The runaway retry in the BCL's interpolation and StringBuilder paths is a side effect it didn't cover. A single extreme value that reaches a log message or string interpolation now hangs the thread instead of failing fast the way ToString() does. Such a value can come from parsing untrusted input or from repeated division.
Suggested fix
In TryFormat, compute the required length the same way ToString() does:
If it exceeds Array.MaxLength, throw the same OverflowException. This is a property of the value, not of the destination.
Return false only when a possible length doesn't fit in destination.
Alternatively, fall back to scientific notation for extreme exponents (option 2 from #75), which makes both paths succeed.
Acceptance criteria
$"{x}" and new StringBuilder().Append(x) for 1e-2147483648 (and for a very large positive exponent) either throw OverflowException or produce scientific text, promptly, matching ToString().
A test runs this under a short timeout.
Existing TryFormat tests still pass, including those that expect false for a genuinely too-small destination.
Notes: Throwing OverflowException when the required length is over Array.MaxLength keeps ToString() and TryFormat consistent and is the smallest fix. Pull the required-length computation into a shared helper so the two paths can't drift apart again. The timeout-guarded test for $"{x}" is the important part of the acceptance criteria.
Activity
matt-edmondson commentedon Sep 30, 2026
Triage
StringBuilder.Appendorstring.Formathangs the thread, or grows buffers until allocation fails, instead of failing fast. Such a value can come from parsing untrusted input. It is also a regression: the PR fix: do the formatting length arithmetic in long #77 fix for Formatting a value with an extreme exponent throws or produces a huge string #75 introduced it.PreciseNumber/PreciseNumber.cs:TryFormat(~L1354) and the length check inToString()(~L503-513) that it should share.TryFormatreturnfalsehere). No duplicate found.OverflowExceptionwhen the required length is overArray.MaxLengthkeepsToString()andTryFormatconsistent and is the smallest fix. Pull the required-length computation into a shared helper so the two paths can't drift apart again. The timeout-guarded test for$"{x}"is the important part of the acceptance criteria.Generated by Claude Code