From 6b8b85ae7b104d2c64d01e4395fb778bdf601db5 Mon Sep 17 00:00:00 2001 From: skyoxZ Date: Wed, 27 Mar 2024 22:17:45 +0800 Subject: [PATCH 1/2] Fix Int128 checked-convert to signed IntX --- .../src/System/Int128.cs | 20 +++++++++++++ .../System/Int128Tests.cs | 30 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index 12cc6c7dec5622..da2c2df354f146 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -265,6 +265,10 @@ public static explicit operator checked short(Int128 value) if (~value._upper == 0) { long lower = (long)value._lower; + if (lower >= 0) + { + ThrowHelper.ThrowOverflowException(); + } return checked((short)lower); } @@ -289,6 +293,10 @@ public static explicit operator checked int(Int128 value) if (~value._upper == 0) { long lower = (long)value._lower; + if (lower >= 0) + { + ThrowHelper.ThrowOverflowException(); + } return checked((int)lower); } @@ -313,6 +321,10 @@ public static explicit operator checked long(Int128 value) if (~value._upper == 0) { long lower = (long)value._lower; + if (lower >= 0) + { + ThrowHelper.ThrowOverflowException(); + } return lower; } @@ -337,6 +349,10 @@ public static explicit operator checked nint(Int128 value) if (~value._upper == 0) { long lower = (long)value._lower; + if (lower >= 0) + { + ThrowHelper.ThrowOverflowException(); + } return checked((nint)lower); } @@ -363,6 +379,10 @@ public static explicit operator checked sbyte(Int128 value) if (~value._upper == 0) { long lower = (long)value._lower; + if (lower >= 0) + { + ThrowHelper.ThrowOverflowException(); + } return checked((sbyte)lower); } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs index 8c1910e2fbd8dc..a9d89720f68c0f 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs @@ -107,6 +107,36 @@ public static void EqualsTest(Int128 i1, object obj, bool expected) Assert.Equal(expected, i1.Equals(obj)); } + [Fact] + public static void CheckedConvertToInt64Overflow() + { + Assert.Throws(() => checked((long)new Int128(ulong.MaxValue, 42))); + } + + [Fact] + public static void CheckedConvertToInt32Overflow() + { + Assert.Throws(() => checked((int)new Int128(ulong.MaxValue, 42))); + } + + [Fact] + public static void CheckedConvertToInt16Overflow() + { + Assert.Throws(() => checked((short)new Int128(ulong.MaxValue, 42))); + } + + [Fact] + public static void CheckedConvertToSByteOverflow() + { + Assert.Throws(() => checked((sbyte)new Int128(ulong.MaxValue, 42))); + } + + [Fact] + public static void CheckedConvertToIntPtrOverflow() + { + Assert.Throws(() => checked((nint)new Int128(ulong.MaxValue, 42))); + } + public static IEnumerable ToString_TestData() { foreach (NumberFormatInfo defaultFormat in new[] { null, NumberFormatInfo.CurrentInfo }) From e01ef8cd4a0ceb7ad9301e33bbb11583a50ec3fa Mon Sep 17 00:00:00 2001 From: skyoxZ Date: Thu, 28 Mar 2024 01:18:35 +0800 Subject: [PATCH 2/2] Simplify implementation --- .../src/System/Int128.cs | 75 ++++--------------- .../System/Int128Tests.cs | 25 +++++-- 2 files changed, 35 insertions(+), 65 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index da2c2df354f146..c1e6c459f7b543 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -262,21 +262,12 @@ public static explicit operator Half(Int128 value) /// is not representable by . public static explicit operator checked short(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - if (lower >= 0) - { - ThrowHelper.ThrowOverflowException(); - } - return checked((short)lower); - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((short)value._lower); + return checked((short)lower); } /// Explicitly converts a 128-bit signed integer to a value. @@ -290,21 +281,12 @@ public static explicit operator checked short(Int128 value) /// is not representable by . public static explicit operator checked int(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - if (lower >= 0) - { - ThrowHelper.ThrowOverflowException(); - } - return checked((int)lower); - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((int)value._lower); + return checked((int)lower); } /// Explicitly converts a 128-bit signed integer to a value. @@ -318,21 +300,12 @@ public static explicit operator checked int(Int128 value) /// is not representable by . public static explicit operator checked long(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - if (lower >= 0) - { - ThrowHelper.ThrowOverflowException(); - } - return lower; - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((long)value._lower); + return lower; } /// Explicitly converts a 128-bit signed integer to a value. @@ -346,21 +319,12 @@ public static explicit operator checked long(Int128 value) /// is not representable by . public static explicit operator checked nint(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - if (lower >= 0) - { - ThrowHelper.ThrowOverflowException(); - } - return checked((nint)lower); - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((nint)value._lower); + return checked((nint)lower); } /// Explicitly converts a 128-bit signed integer to a value. @@ -376,21 +340,12 @@ public static explicit operator checked nint(Int128 value) [CLSCompliant(false)] public static explicit operator checked sbyte(Int128 value) { - if (~value._upper == 0) - { - long lower = (long)value._lower; - if (lower >= 0) - { - ThrowHelper.ThrowOverflowException(); - } - return checked((sbyte)lower); - } - - if (value._upper != 0) + long lower = (long)value._lower; + if ((long)value._upper != lower >> 63) { ThrowHelper.ThrowOverflowException(); } - return checked((sbyte)value._lower); + return checked((sbyte)lower); } /// Explicitly converts a 128-bit signed integer to a value. diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs index a9d89720f68c0f..9b9103b56ec20c 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.cs @@ -108,32 +108,47 @@ public static void EqualsTest(Int128 i1, object obj, bool expected) } [Fact] - public static void CheckedConvertToInt64Overflow() + public static void CheckedConvertToInt64() { + Assert.Equal(123L, checked((long)new Int128(0, 123))); + Assert.Equal(-123L, checked((long)(Int128)(-123))); + Assert.Throws(() => checked((long)new Int128(1, 1))); Assert.Throws(() => checked((long)new Int128(ulong.MaxValue, 42))); } [Fact] - public static void CheckedConvertToInt32Overflow() + public static void CheckedConvertToInt32() { + Assert.Equal(123, checked((int)new Int128(0, 123))); + Assert.Equal(-123, checked((int)(Int128)(-123))); + Assert.Throws(() => checked((int)new Int128(1, 1))); Assert.Throws(() => checked((int)new Int128(ulong.MaxValue, 42))); } [Fact] - public static void CheckedConvertToInt16Overflow() + public static void CheckedConvertToInt16() { + Assert.Equal((short)123, checked((short)new Int128(0, 123))); + Assert.Equal((short)(-123), checked((short)(Int128)(-123))); + Assert.Throws(() => checked((short)new Int128(1, 1))); Assert.Throws(() => checked((short)new Int128(ulong.MaxValue, 42))); } [Fact] - public static void CheckedConvertToSByteOverflow() + public static void CheckedConvertToSByte() { + Assert.Equal((sbyte)123, checked((sbyte)new Int128(0, 123))); + Assert.Equal((sbyte)(-123), checked((sbyte)(Int128)(-123))); + Assert.Throws(() => checked((sbyte)new Int128(1, 1))); Assert.Throws(() => checked((sbyte)new Int128(ulong.MaxValue, 42))); } [Fact] - public static void CheckedConvertToIntPtrOverflow() + public static void CheckedConvertToIntPtr() { + Assert.Equal((nint)123, checked((nint)new Int128(0, 123))); + Assert.Equal((nint)(-123), checked((nint)(Int128)(-123))); + Assert.Throws(() => checked((nint)new Int128(1, 1))); Assert.Throws(() => checked((nint)new Int128(ulong.MaxValue, 42))); }