diff options
author | Tanner Gooding <tagoo@microsoft.com> | 2022-02-15 19:25:37 +0300 |
---|---|---|
committer | Matt Mitchell <mmitche@microsoft.com> | 2022-02-15 19:25:37 +0300 |
commit | 3065735be79d6b7d17e8e3a723115810b43c9b3a (patch) | |
tree | 560d5ec8dc053ae0e391bd1600f099714f6bd286 | |
parent | f4567ec9864f30f27f6672d882ea98db754149bb (diff) |
Merged PR 21171: Fixing the shift-left handling to correctly account for overshiftingv5.0.15
Fixing the shift-left handling to correctly account for overshifting
-rw-r--r-- | src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs | 44 |
1 files changed, 32 insertions, 12 deletions
diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs b/src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs index ccea6055d7b..8c8d28c5880 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs @@ -31,7 +31,9 @@ namespace System private const int MaxBits = BitsForLongestBinaryMantissa + BitsForLongestDigitSequence + BitsPerBlock; private const int BitsPerBlock = sizeof(int) * 8; - private const int MaxBlockCount = (MaxBits + (BitsPerBlock - 1)) / BitsPerBlock; + + // We need one extra block to make our shift left algorithm significantly simpler + private const int MaxBlockCount = ((MaxBits + (BitsPerBlock - 1)) / BitsPerBlock) + 1; private static readonly uint[] s_Pow10UInt32Table = new uint[] { @@ -302,7 +304,8 @@ namespace System 0xD9D61A05, 0x00000325, - // 9 Trailing blocks to ensure MaxBlockCount + // 10 Trailing blocks to ensure MaxBlockCount + 0x00000000, 0x00000000, 0x00000000, 0x00000000, @@ -1205,19 +1208,21 @@ namespace System int readIndex = (length - 1); int writeIndex = readIndex + (int)(blocksToShift); - uint remainingBitsInLastBlock = (uint)BitOperations.LeadingZeroCount(_blocks[readIndex]); - - if (remainingBitsToShift > remainingBitsInLastBlock) - { - // We need an extra block for the partial shift - writeIndex++; - } - - Debug.Assert(unchecked((uint)(writeIndex)) < MaxBlockCount); - // Check if the shift is block aligned if (remainingBitsToShift == 0) { + Debug.Assert(unchecked((uint)(length)) < MaxBlockCount); + + if (unchecked((uint)(length)) >= MaxBlockCount) + { + // We shouldn't reach here, and the above assert will help flag this + // during testing, but we'll ensure that we return a safe value of + // zero in the case we end up overflowing in any way. + + SetZero(out this); + return; + } + while (readIndex >= 0) { _blocks[writeIndex] = _blocks[readIndex]; @@ -1232,6 +1237,21 @@ namespace System } else { + // We need an extra block for the partial shift + + writeIndex++; + Debug.Assert(unchecked((uint)(length)) < MaxBlockCount); + + if (unchecked((uint)(length)) >= MaxBlockCount) + { + // We shouldn't reach here, and the above assert will help flag this + // during testing, but we'll ensure that we return a safe value of + // zero in the case we end up overflowing in any way. + + SetZero(out this); + return; + } + // Set the length to hold the shifted blocks _length = writeIndex + 1; |