Skip to content

Commit

Permalink
Merged PR 21171: Fixing the shift-left handling to correctly account …
Browse files Browse the repository at this point in the history
…for overshifting

Fixing the shift-left handling to correctly account for overshifting
  • Loading branch information
tannergooding authored and mmitche committed Feb 15, 2022
1 parent f4567ec commit 3065735
Showing 1 changed file with 32 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ internal unsafe ref struct BigInteger
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[]
{
Expand Down Expand Up @@ -302,7 +304,8 @@ internal unsafe ref struct BigInteger
0xD9D61A05,
0x00000325,

// 9 Trailing blocks to ensure MaxBlockCount
// 10 Trailing blocks to ensure MaxBlockCount
0x00000000,
0x00000000,
0x00000000,
0x00000000,
Expand Down Expand Up @@ -1205,19 +1208,21 @@ public void ShiftLeft(uint shift)
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];
Expand All @@ -1232,6 +1237,21 @@ public void ShiftLeft(uint shift)
}
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;

Expand Down

0 comments on commit 3065735

Please sign in to comment.