Browse Source

Fix overflow approximating fractions of large negative constants

FractionApprox rejects inputs above 0x7FFFFFFF because they cannot be stored
as a fraction, but the check was one-sided while the sign is stripped right
after it. A large negative value therefore reached the continued-fraction loop
and overflowed the terms it accumulates. ICSharpCode.Decompiler is built with
CheckForOverflowUnderflow, so that aborted decompilation of the whole member
instead of wrapping.

Found by fuzzing nuget.org; reproduces on MathNet.Numerics, whose constants
reach the approximation through their ratio to PI.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
pull/3956/head
Siegfried Pammer 1 month ago committed by Siegfried Pammer
parent
commit
6e218fa979
  1. 5
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.cs
  2. 5
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

5
ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.cs

@ -202,5 +202,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -202,5 +202,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public const double Double_Negated_E = -Math.E;
public const double Double_Negated_BeforeE = -2.7182818284590446;
public const double Double_Negated_AfterE = -2.7182818284590455;
// Values of either sign whose ratio to PI or E is outside the range expressible as
// a fraction must be left alone rather than run through the approximation.
public const double Double_TooLargeForFraction = 3085105840164255.5;
public const double Double_Negated_TooLargeForFraction = -3085105840164255.5;
}
}

5
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -1724,7 +1724,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1724,7 +1724,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
// we just keep the last partial product of these matrices.
static (long Num, long Den) FractionApprox(double value, int maxDenominator)
{
if (value > 0x7FFFFFFF)
// The range check has to be on the magnitude: the sign is stripped below, so a
// large negative value would otherwise reach the continued-fraction loop and
// overflow the terms it accumulates.
if (Math.Abs(value) > 0x7FFFFFFF)
return (0, 0);
double startValue = value;

Loading…
Cancel
Save