Skip to content

Commit 8f19f4e

Browse files
authored
Fix possible stack overflow in TotalOrderIeee754Comparer (#86593)
* Fix possible stack overflow in TotalOrderIeee754Comparer * Add a test
1 parent 2bdbb89 commit 8f19f4e

File tree

2 files changed

+244
-2
lines changed

2 files changed

+244
-2
lines changed

src/libraries/System.Private.CoreLib/src/System/Numerics/TotalOrderIeee754Comparer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ static int CompareSignificand(T x, T y)
155155
int xSignificandLength = x.GetSignificandByteCount();
156156
int ySignificandLength = y.GetSignificandByteCount();
157157

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

161161
x.WriteSignificandBigEndian(significandX);
162162
y.WriteSignificandBigEndian(significandY);

src/libraries/System.Runtime/tests/System/Numerics/TotalOrderIeee754ComparerTests.cs

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Collections.Generic;
5+
using System.Globalization;
56
using System.Numerics;
67
using System.Runtime.InteropServices;
78
using Xunit;
@@ -100,5 +101,246 @@ public void TotalOrderTestNFloat(float x, float y, int result)
100101
var comparer = new TotalOrderIeee754Comparer<NFloat>();
101102
Assert.Equal(result, Math.Sign(comparer.Compare(x, y)));
102103
}
104+
105+
[Theory]
106+
[InlineData(-1)]
107+
[InlineData(int.MinValue)]
108+
public void TotalOrderTestInvalidSignificand(int significandByteCount)
109+
{
110+
var comparer = new TotalOrderIeee754Comparer<StubFloatingPointIeee754>();
111+
StubFloatingPointIeee754 xy = new StubFloatingPointIeee754(1, significandByteCount);
112+
Assert.Throws<OverflowException>(() => comparer.Compare(xy, xy));
113+
}
114+
115+
private readonly struct StubFloatingPointIeee754 : IFloatingPointIeee754<StubFloatingPointIeee754>
116+
{
117+
private readonly int _significandBitLength;
118+
private readonly int _significandByteCount;
119+
120+
public StubFloatingPointIeee754(int significandBitLength, int significandByteCount)
121+
{
122+
_significandBitLength = significandBitLength;
123+
_significandByteCount = significandByteCount;
124+
}
125+
126+
public static StubFloatingPointIeee754 Epsilon => default;
127+
public static StubFloatingPointIeee754 NaN => default;
128+
public static StubFloatingPointIeee754 NegativeInfinity => default;
129+
public static StubFloatingPointIeee754 NegativeZero => default;
130+
public static StubFloatingPointIeee754 PositiveInfinity => default;
131+
public static StubFloatingPointIeee754 NegativeOne => default;
132+
public static StubFloatingPointIeee754 E => default;
133+
public static StubFloatingPointIeee754 Pi => default;
134+
public static StubFloatingPointIeee754 Tau => default;
135+
public static StubFloatingPointIeee754 One => default;
136+
public static int Radix => default;
137+
public static StubFloatingPointIeee754 Zero => default;
138+
public static StubFloatingPointIeee754 AdditiveIdentity => default;
139+
public static StubFloatingPointIeee754 MultiplicativeIdentity => default;
140+
public static StubFloatingPointIeee754 Abs(StubFloatingPointIeee754 value) => default;
141+
public static StubFloatingPointIeee754 Acos(StubFloatingPointIeee754 x) => default;
142+
public static StubFloatingPointIeee754 Acosh(StubFloatingPointIeee754 x) => default;
143+
public static StubFloatingPointIeee754 AcosPi(StubFloatingPointIeee754 x) => default;
144+
public static StubFloatingPointIeee754 Asin(StubFloatingPointIeee754 x) => default;
145+
public static StubFloatingPointIeee754 Asinh(StubFloatingPointIeee754 x) => default;
146+
public static StubFloatingPointIeee754 AsinPi(StubFloatingPointIeee754 x) => default;
147+
public static StubFloatingPointIeee754 Atan(StubFloatingPointIeee754 x) => default;
148+
public static StubFloatingPointIeee754 Atan2(StubFloatingPointIeee754 y, StubFloatingPointIeee754 x) => default;
149+
public static StubFloatingPointIeee754 Atan2Pi(StubFloatingPointIeee754 y, StubFloatingPointIeee754 x) => default;
150+
public static StubFloatingPointIeee754 Atanh(StubFloatingPointIeee754 x) => default;
151+
public static StubFloatingPointIeee754 AtanPi(StubFloatingPointIeee754 x) => default;
152+
public static StubFloatingPointIeee754 BitDecrement(StubFloatingPointIeee754 x) => default;
153+
public static StubFloatingPointIeee754 BitIncrement(StubFloatingPointIeee754 x) => default;
154+
public static StubFloatingPointIeee754 Cbrt(StubFloatingPointIeee754 x) => default;
155+
public static StubFloatingPointIeee754 Cos(StubFloatingPointIeee754 x) => default;
156+
public static StubFloatingPointIeee754 Cosh(StubFloatingPointIeee754 x) => default;
157+
public static StubFloatingPointIeee754 CosPi(StubFloatingPointIeee754 x) => default;
158+
public static StubFloatingPointIeee754 Exp(StubFloatingPointIeee754 x) => default;
159+
public static StubFloatingPointIeee754 Exp10(StubFloatingPointIeee754 x) => default;
160+
public static StubFloatingPointIeee754 Exp2(StubFloatingPointIeee754 x) => default;
161+
public static StubFloatingPointIeee754 FusedMultiplyAdd(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right, StubFloatingPointIeee754 addend) => default;
162+
public static StubFloatingPointIeee754 Hypot(StubFloatingPointIeee754 x, StubFloatingPointIeee754 y) => default;
163+
public static StubFloatingPointIeee754 Ieee754Remainder(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => default;
164+
public static int ILogB(StubFloatingPointIeee754 x) => default;
165+
public static bool IsCanonical(StubFloatingPointIeee754 value) => true;
166+
public static bool IsComplexNumber(StubFloatingPointIeee754 value) => false;
167+
public static bool IsEvenInteger(StubFloatingPointIeee754 value) => false;
168+
public static bool IsFinite(StubFloatingPointIeee754 value) => false;
169+
public static bool IsImaginaryNumber(StubFloatingPointIeee754 value) => false;
170+
public static bool IsInfinity(StubFloatingPointIeee754 value) => false;
171+
public static bool IsInteger(StubFloatingPointIeee754 value) => false;
172+
public static bool IsNaN(StubFloatingPointIeee754 value) => true;
173+
public static bool IsNegative(StubFloatingPointIeee754 value) => false;
174+
public static bool IsNegativeInfinity(StubFloatingPointIeee754 value) => false;
175+
public static bool IsNormal(StubFloatingPointIeee754 value) => false;
176+
public static bool IsOddInteger(StubFloatingPointIeee754 value) => false;
177+
public static bool IsPositive(StubFloatingPointIeee754 value) => false;
178+
public static bool IsPositiveInfinity(StubFloatingPointIeee754 value) => false;
179+
public static bool IsRealNumber(StubFloatingPointIeee754 value) => false;
180+
public static bool IsSubnormal(StubFloatingPointIeee754 value) => false;
181+
public static bool IsZero(StubFloatingPointIeee754 value) => false;
182+
public static StubFloatingPointIeee754 Log(StubFloatingPointIeee754 x) => default;
183+
public static StubFloatingPointIeee754 Log(StubFloatingPointIeee754 x, StubFloatingPointIeee754 newBase) => default;
184+
public static StubFloatingPointIeee754 Log10(StubFloatingPointIeee754 x) => default;
185+
public static StubFloatingPointIeee754 Log2(StubFloatingPointIeee754 x) => default;
186+
public static StubFloatingPointIeee754 MaxMagnitude(StubFloatingPointIeee754 x, StubFloatingPointIeee754 y) => default;
187+
public static StubFloatingPointIeee754 MaxMagnitudeNumber(StubFloatingPointIeee754 x, StubFloatingPointIeee754 y) => default;
188+
public static StubFloatingPointIeee754 MinMagnitude(StubFloatingPointIeee754 x, StubFloatingPointIeee754 y) => default;
189+
public static StubFloatingPointIeee754 MinMagnitudeNumber(StubFloatingPointIeee754 x, StubFloatingPointIeee754 y) => default;
190+
public static StubFloatingPointIeee754 Parse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider) => default;
191+
public static StubFloatingPointIeee754 Parse(string s, NumberStyles style, IFormatProvider? provider) => default;
192+
public static StubFloatingPointIeee754 Parse(ReadOnlySpan<char> s, IFormatProvider? provider) => default;
193+
public static StubFloatingPointIeee754 Parse(string s, IFormatProvider? provider) => default;
194+
public static StubFloatingPointIeee754 Pow(StubFloatingPointIeee754 x, StubFloatingPointIeee754 y) => default;
195+
public static StubFloatingPointIeee754 RootN(StubFloatingPointIeee754 x, int n) => default;
196+
public static StubFloatingPointIeee754 Round(StubFloatingPointIeee754 x, int digits, MidpointRounding mode) => default;
197+
public static StubFloatingPointIeee754 ScaleB(StubFloatingPointIeee754 x, int n) => default;
198+
public static StubFloatingPointIeee754 Sin(StubFloatingPointIeee754 x) => default;
199+
public static (StubFloatingPointIeee754 Sin, StubFloatingPointIeee754 Cos) SinCos(StubFloatingPointIeee754 x) => default;
200+
public static (StubFloatingPointIeee754 SinPi, StubFloatingPointIeee754 CosPi) SinCosPi(StubFloatingPointIeee754 x) => default;
201+
public static StubFloatingPointIeee754 Sinh(StubFloatingPointIeee754 x) => default;
202+
public static StubFloatingPointIeee754 SinPi(StubFloatingPointIeee754 x) => default;
203+
public static StubFloatingPointIeee754 Sqrt(StubFloatingPointIeee754 x) => default;
204+
public static StubFloatingPointIeee754 Tan(StubFloatingPointIeee754 x) => default;
205+
public static StubFloatingPointIeee754 Tanh(StubFloatingPointIeee754 x) => default;
206+
public static StubFloatingPointIeee754 TanPi(StubFloatingPointIeee754 x) => default;
207+
208+
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out StubFloatingPointIeee754 result)
209+
{
210+
result = default;
211+
return false;
212+
}
213+
214+
public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out StubFloatingPointIeee754 result)
215+
{
216+
result = default;
217+
return false;
218+
}
219+
220+
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, out StubFloatingPointIeee754 result)
221+
{
222+
result = default;
223+
return false;
224+
}
225+
226+
public static bool TryParse(string? s, IFormatProvider? provider, out StubFloatingPointIeee754 result)
227+
{
228+
result = default;
229+
return false;
230+
}
231+
232+
static bool INumberBase<StubFloatingPointIeee754>.TryConvertFromChecked<TOther>(TOther value, out StubFloatingPointIeee754 result)
233+
{
234+
result = default;
235+
return false;
236+
}
237+
238+
static bool INumberBase<StubFloatingPointIeee754>.TryConvertFromSaturating<TOther>(TOther value, out StubFloatingPointIeee754 result)
239+
{
240+
result = default;
241+
return false;
242+
}
243+
244+
static bool INumberBase<StubFloatingPointIeee754>.TryConvertFromTruncating<TOther>(TOther value, out StubFloatingPointIeee754 result)
245+
{
246+
result = default;
247+
return false;
248+
}
249+
250+
static bool INumberBase<StubFloatingPointIeee754>.TryConvertToChecked<TOther>(StubFloatingPointIeee754 value, out TOther result)
251+
{
252+
result = default;
253+
return false;
254+
}
255+
256+
static bool INumberBase<StubFloatingPointIeee754>.TryConvertToSaturating<TOther>(StubFloatingPointIeee754 value, out TOther result)
257+
{
258+
result = default;
259+
return false;
260+
}
261+
262+
static bool INumberBase<StubFloatingPointIeee754>.TryConvertToTruncating<TOther>(StubFloatingPointIeee754 value, out TOther result)
263+
{
264+
result = default;
265+
return false;
266+
}
267+
268+
public int CompareTo(object? obj) => 1;
269+
270+
public int CompareTo(StubFloatingPointIeee754 other) => 1;
271+
272+
public bool Equals(StubFloatingPointIeee754 other) => false;
273+
274+
public int GetExponentByteCount() => 0;
275+
276+
public int GetExponentShortestBitLength() => 0;
277+
278+
public int GetSignificandBitLength() => _significandBitLength;
279+
280+
public int GetSignificandByteCount() => _significandByteCount;
281+
282+
public string ToString(string? format, IFormatProvider? formatProvider) => string.Empty;
283+
284+
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
285+
{
286+
charsWritten = 0;
287+
return false;
288+
}
289+
290+
public bool TryWriteExponentBigEndian(Span<byte> destination, out int bytesWritten)
291+
{
292+
bytesWritten = 0;
293+
return false;
294+
}
295+
296+
public bool TryWriteExponentLittleEndian(Span<byte> destination, out int bytesWritten)
297+
{
298+
bytesWritten = 0;
299+
return false;
300+
}
301+
302+
public bool TryWriteSignificandBigEndian(Span<byte> destination, out int bytesWritten)
303+
{
304+
if (destination.Length >= _significandByteCount)
305+
{
306+
bytesWritten = _significandByteCount;
307+
return true;
308+
}
309+
310+
bytesWritten = 0;
311+
return false;
312+
}
313+
314+
public bool TryWriteSignificandLittleEndian(Span<byte> destination, out int bytesWritten)
315+
{
316+
if (destination.Length >= _significandByteCount)
317+
{
318+
bytesWritten = _significandByteCount;
319+
return true;
320+
}
321+
322+
bytesWritten = 0;
323+
return false;
324+
}
325+
326+
public override bool Equals(object o) => false;
327+
public override int GetHashCode() => 0;
328+
329+
public static StubFloatingPointIeee754 operator +(StubFloatingPointIeee754 value) => default;
330+
public static StubFloatingPointIeee754 operator +(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => default;
331+
public static StubFloatingPointIeee754 operator -(StubFloatingPointIeee754 value) => default;
332+
public static StubFloatingPointIeee754 operator -(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => default;
333+
public static StubFloatingPointIeee754 operator ++(StubFloatingPointIeee754 value) => default;
334+
public static StubFloatingPointIeee754 operator --(StubFloatingPointIeee754 value) => default;
335+
public static StubFloatingPointIeee754 operator *(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => default;
336+
public static StubFloatingPointIeee754 operator /(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => default;
337+
public static StubFloatingPointIeee754 operator %(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => default;
338+
public static bool operator ==(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => false;
339+
public static bool operator !=(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => false;
340+
public static bool operator <(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => false;
341+
public static bool operator >(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => false;
342+
public static bool operator <=(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => false;
343+
public static bool operator >=(StubFloatingPointIeee754 left, StubFloatingPointIeee754 right) => false;
344+
}
103345
}
104346
}

0 commit comments

Comments
 (0)