Fix incorrect result right shifting specific negative BigInteger by 32 bits (#54115)
authorWei Zheng <13881045+wzchua@users.noreply.github.com>
Sat, 24 Jul 2021 04:32:45 +0000 (12:32 +0800)
committerGitHub <noreply@github.com>
Sat, 24 Jul 2021 04:32:45 +0000 (00:32 -0400)
src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs
src/libraries/System.Runtime.Numerics/tests/BigInteger/op_rightshift.cs

index aa90a8b..ffee155 100644 (file)
@@ -1996,6 +1996,7 @@ namespace System.Numerics
             Span<uint> stackallocedXd = stackalloc uint[1];
             Span<uint> xd = stackallocedXd;
             bool negx = GetPartsForBitManipulation(ref value, ref xd);
+            bool trackSignBit = false;
 
             if (negx)
             {
@@ -2020,9 +2021,13 @@ namespace System.Numerics
                 }
 
                 NumericsHelpers.DangerousMakeTwosComplement(xd); // Mutates xd
+                if (xd[^1] == 0)
+                {
+                    trackSignBit = true;
+                }
             }
 
-            int zl = xd.Length - digitShift;
+            int zl = xd.Length - digitShift + (trackSignBit ? 1: 0);
             uint[]? zdArray = null;
             Span<uint> zd = stackalloc uint[0];
             if (zl > 0)
@@ -2057,6 +2062,11 @@ namespace System.Numerics
             if (negx)
             {
                 NumericsHelpers.DangerousMakeTwosComplement(zd); // Mutates zd
+
+                if (trackSignBit)
+                {
+                    zd[^1] = 1;
+                }
             }
 
             return new BigInteger(zd, zdArray, negx);
index 5107f0e..0e7fbf1 100644 (file)
@@ -54,6 +54,15 @@ namespace System.Numerics.Tests
                 tempByteArray2 = new byte[] { (byte)32 };
                 VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
             }
+
+            // RightShift Method - All One Uint Large BigIntegers - 32 bit Shift
+            for (int i = 0; i < s_samples; i++)
+            {
+                tempByteArray1 = GetRandomLengthAllOnesUIntByteArray(s_random);
+                tempByteArray2 = new byte[] { (byte)32 };
+                VerifyRightShiftString(Print(tempByteArray2) + Print(tempByteArray1) + "b>>");
+            }
+
             // RightShift Method - Large BigIntegers - large - Shift
             for (int i = 0; i < s_samples; i++)
             {
@@ -211,6 +220,16 @@ namespace System.Numerics.Tests
             return value;
         }
 
+        private static byte[] GetRandomLengthAllOnesUIntByteArray(Random random)
+        {
+            int gap = random.Next(0, 128);
+            int byteLength = 4 + gap * 4 + 1;
+            byte[] array = new byte[byteLength];
+            array[0] = 1;
+            array[^1] = 0xFF;
+            return array;
+        }
+
         private static string Print(byte[] bytes)
         {
             return MyBigIntImp.Print(bytes);