Skip to content

Commit

Permalink
Fix possible stack overflow in TotalOrderIeee754Comparer (#86593)
Browse files Browse the repository at this point in the history
* Fix possible stack overflow in TotalOrderIeee754Comparer

* Add a test
  • Loading branch information
vcsjones authored May 23, 2023
1 parent 2bdbb89 commit 8f19f4e
Show file tree
Hide file tree
Showing 2 changed files with 244 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ static int CompareSignificand(T x, T y)
int xSignificandLength = x.GetSignificandByteCount();
int ySignificandLength = y.GetSignificandByteCount();

Span<byte> significandX = xSignificandLength <= StackAllocThreshold ? stackalloc byte[xSignificandLength] : new byte[xSignificandLength];
Span<byte> significandY = ySignificandLength <= StackAllocThreshold ? stackalloc byte[ySignificandLength] : new byte[ySignificandLength];
Span<byte> significandX = (uint)xSignificandLength <= StackAllocThreshold ? stackalloc byte[xSignificandLength] : new byte[xSignificandLength];
Span<byte> significandY = (uint)ySignificandLength <= StackAllocThreshold ? stackalloc byte[ySignificandLength] : new byte[ySignificandLength];

x.WriteSignificandBigEndian(significandX);
y.WriteSignificandBigEndian(significandY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Globalization;
using System.Numerics;
using System.Runtime.InteropServices;
using Xunit;
Expand Down Expand Up @@ -100,5 +101,246 @@ public void TotalOrderTestNFloat(float x, float y, int result)
var comparer = new TotalOrderIeee754Comparer<NFloat>();
Assert.Equal(result, Math.Sign(comparer.Compare(x, y)));
}

[Theory]
[InlineData(-1)]
[InlineData(int.MinValue)]
public void TotalOrderTestInvalidSignificand(int significandByteCount)
{
var comparer = new TotalOrderIeee754Comparer<StubFloatingPointIeee754>();
StubFloatingPointIeee754 xy = new StubFloatingPointIeee754(1, significandByteCount);
Assert.Throws<OverflowException>(() => comparer.Compare(xy, xy));
}

private readonly struct StubFloatingPointIeee754 : IFloatingPointIeee754<StubFloatingPointIeee754>
{
private readonly int _significandBitLength;
private readonly int _significandByteCount;

public StubFloatingPointIeee754(int significandBitLength, int significandByteCount)
{
_significandBitLength = significandBitLength;
_significandByteCount = significandByteCount;
}

public static StubFloatingPointIeee754 Epsilon => default;
public static StubFloatingPointIeee754 NaN => default;
public static StubFloatingPointIeee754 NegativeInfinity => default;
public static StubFloatingPointIeee754 NegativeZero => default;
public static StubFloatingPointIeee754 PositiveInfinity => default;
public static StubFloatingPointIeee754 NegativeOne => default;
public static StubFloatingPointIeee754 E => default;
public static StubFloatingPointIeee754 Pi => default;
public static StubFloatingPointIeee754 Tau => default;
public static StubFloatingPointIeee754 One => default;
public static int Radix => default;
public static StubFloatingPointIeee754 Zero => default;
public static StubFloatingPointIeee754 AdditiveIdentity => default;
public static StubFloatingPointIeee754 MultiplicativeIdentity => default;
public static StubFloatingPointIeee754 Abs(StubFloatingPointIeee754 value) => default;
public static StubFloatingPointIeee754 Acos(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Acosh(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 AcosPi(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Asin(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Asinh(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 AsinPi(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Atan(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Atan2(StubFloatingPointIeee754 y, StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Atan2Pi(StubFloatingPointIeee754 y, StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Atanh(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 AtanPi(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 BitDecrement(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 BitIncrement(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Cbrt(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Cos(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Cosh(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 CosPi(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Exp(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Exp10(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Exp2(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 FusedMultiplyAdd(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right, StubFloatingPointIeee754 addend) => default;
public static StubFloatingPointIeee754 Hypot(StubFloatingPointIeee754 x, StubFloatingPointIeee754 y) => default;
public static StubFloatingPointIeee754 Ieee754Remainder(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => default;
public static int ILogB(StubFloatingPointIeee754 x) => default;
public static bool IsCanonical(StubFloatingPointIeee754 value) => true;
public static bool IsComplexNumber(StubFloatingPointIeee754 value) => false;
public static bool IsEvenInteger(StubFloatingPointIeee754 value) => false;
public static bool IsFinite(StubFloatingPointIeee754 value) => false;
public static bool IsImaginaryNumber(StubFloatingPointIeee754 value) => false;
public static bool IsInfinity(StubFloatingPointIeee754 value) => false;
public static bool IsInteger(StubFloatingPointIeee754 value) => false;
public static bool IsNaN(StubFloatingPointIeee754 value) => true;
public static bool IsNegative(StubFloatingPointIeee754 value) => false;
public static bool IsNegativeInfinity(StubFloatingPointIeee754 value) => false;
public static bool IsNormal(StubFloatingPointIeee754 value) => false;
public static bool IsOddInteger(StubFloatingPointIeee754 value) => false;
public static bool IsPositive(StubFloatingPointIeee754 value) => false;
public static bool IsPositiveInfinity(StubFloatingPointIeee754 value) => false;
public static bool IsRealNumber(StubFloatingPointIeee754 value) => false;
public static bool IsSubnormal(StubFloatingPointIeee754 value) => false;
public static bool IsZero(StubFloatingPointIeee754 value) => false;
public static StubFloatingPointIeee754 Log(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Log(StubFloatingPointIeee754 x, StubFloatingPointIeee754 newBase) => default;
public static StubFloatingPointIeee754 Log10(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Log2(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 MaxMagnitude(StubFloatingPointIeee754 x, StubFloatingPointIeee754 y) => default;
public static StubFloatingPointIeee754 MaxMagnitudeNumber(StubFloatingPointIeee754 x, StubFloatingPointIeee754 y) => default;
public static StubFloatingPointIeee754 MinMagnitude(StubFloatingPointIeee754 x, StubFloatingPointIeee754 y) => default;
public static StubFloatingPointIeee754 MinMagnitudeNumber(StubFloatingPointIeee754 x, StubFloatingPointIeee754 y) => default;
public static StubFloatingPointIeee754 Parse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider) => default;
public static StubFloatingPointIeee754 Parse(string s, NumberStyles style, IFormatProvider? provider) => default;
public static StubFloatingPointIeee754 Parse(ReadOnlySpan<char> s, IFormatProvider? provider) => default;
public static StubFloatingPointIeee754 Parse(string s, IFormatProvider? provider) => default;
public static StubFloatingPointIeee754 Pow(StubFloatingPointIeee754 x, StubFloatingPointIeee754 y) => default;
public static StubFloatingPointIeee754 RootN(StubFloatingPointIeee754 x, int n) => default;
public static StubFloatingPointIeee754 Round(StubFloatingPointIeee754 x, int digits, MidpointRounding mode) => default;
public static StubFloatingPointIeee754 ScaleB(StubFloatingPointIeee754 x, int n) => default;
public static StubFloatingPointIeee754 Sin(StubFloatingPointIeee754 x) => default;
public static (StubFloatingPointIeee754 Sin, StubFloatingPointIeee754 Cos) SinCos(StubFloatingPointIeee754 x) => default;
public static (StubFloatingPointIeee754 SinPi, StubFloatingPointIeee754 CosPi) SinCosPi(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Sinh(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 SinPi(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Sqrt(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Tan(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 Tanh(StubFloatingPointIeee754 x) => default;
public static StubFloatingPointIeee754 TanPi(StubFloatingPointIeee754 x) => default;

public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out StubFloatingPointIeee754 result)
{
result = default;
return false;
}

public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out StubFloatingPointIeee754 result)
{
result = default;
return false;
}

public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, out StubFloatingPointIeee754 result)
{
result = default;
return false;
}

public static bool TryParse(string? s, IFormatProvider? provider, out StubFloatingPointIeee754 result)
{
result = default;
return false;
}

static bool INumberBase<StubFloatingPointIeee754>.TryConvertFromChecked<TOther>(TOther value, out StubFloatingPointIeee754 result)
{
result = default;
return false;
}

static bool INumberBase<StubFloatingPointIeee754>.TryConvertFromSaturating<TOther>(TOther value, out StubFloatingPointIeee754 result)
{
result = default;
return false;
}

static bool INumberBase<StubFloatingPointIeee754>.TryConvertFromTruncating<TOther>(TOther value, out StubFloatingPointIeee754 result)
{
result = default;
return false;
}

static bool INumberBase<StubFloatingPointIeee754>.TryConvertToChecked<TOther>(StubFloatingPointIeee754 value, out TOther result)
{
result = default;
return false;
}

static bool INumberBase<StubFloatingPointIeee754>.TryConvertToSaturating<TOther>(StubFloatingPointIeee754 value, out TOther result)
{
result = default;
return false;
}

static bool INumberBase<StubFloatingPointIeee754>.TryConvertToTruncating<TOther>(StubFloatingPointIeee754 value, out TOther result)
{
result = default;
return false;
}

public int CompareTo(object? obj) => 1;

public int CompareTo(StubFloatingPointIeee754 other) => 1;

public bool Equals(StubFloatingPointIeee754 other) => false;

public int GetExponentByteCount() => 0;

public int GetExponentShortestBitLength() => 0;

public int GetSignificandBitLength() => _significandBitLength;

public int GetSignificandByteCount() => _significandByteCount;

public string ToString(string? format, IFormatProvider? formatProvider) => string.Empty;

public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
{
charsWritten = 0;
return false;
}

public bool TryWriteExponentBigEndian(Span<byte> destination, out int bytesWritten)
{
bytesWritten = 0;
return false;
}

public bool TryWriteExponentLittleEndian(Span<byte> destination, out int bytesWritten)
{
bytesWritten = 0;
return false;
}

public bool TryWriteSignificandBigEndian(Span<byte> destination, out int bytesWritten)
{
if (destination.Length >= _significandByteCount)
{
bytesWritten = _significandByteCount;
return true;
}

bytesWritten = 0;
return false;
}

public bool TryWriteSignificandLittleEndian(Span<byte> destination, out int bytesWritten)
{
if (destination.Length >= _significandByteCount)
{
bytesWritten = _significandByteCount;
return true;
}

bytesWritten = 0;
return false;
}

public override bool Equals(object o) => false;
public override int GetHashCode() => 0;

public static StubFloatingPointIeee754 operator +(StubFloatingPointIeee754 value) => default;
public static StubFloatingPointIeee754 operator +(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => default;
public static StubFloatingPointIeee754 operator -(StubFloatingPointIeee754 value) => default;
public static StubFloatingPointIeee754 operator -(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => default;
public static StubFloatingPointIeee754 operator ++(StubFloatingPointIeee754 value) => default;
public static StubFloatingPointIeee754 operator --(StubFloatingPointIeee754 value) => default;
public static StubFloatingPointIeee754 operator *(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => default;
public static StubFloatingPointIeee754 operator /(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => default;
public static StubFloatingPointIeee754 operator %(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => default;
public static bool operator ==(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => false;
public static bool operator !=(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => false;
public static bool operator <(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => false;
public static bool operator >(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => false;
public static bool operator <=(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => false;
public static bool operator >=(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => false;
}
}
}

0 comments on commit 8f19f4e

Please sign in to comment.