@@ -31,7 +31,9 @@ internal unsafe ref struct BigInteger
3131 private const int MaxBits = BitsForLongestBinaryMantissa + BitsForLongestDigitSequence + BitsPerBlock ;
3232
3333 private const int BitsPerBlock = sizeof ( int ) * 8 ;
34- private const int MaxBlockCount = ( MaxBits + ( BitsPerBlock - 1 ) ) / BitsPerBlock ;
34+
35+ // We need one extra block to make our shift left algorithm significantly simpler
36+ private const int MaxBlockCount = ( ( MaxBits + ( BitsPerBlock - 1 ) ) / BitsPerBlock ) + 1 ;
3537
3638 private static readonly uint [ ] s_Pow10UInt32Table = new uint [ ]
3739 {
@@ -302,7 +304,8 @@ internal unsafe ref struct BigInteger
302304 0xD9D61A05 ,
303305 0x00000325 ,
304306
305- // 9 Trailing blocks to ensure MaxBlockCount
307+ // 10 Trailing blocks to ensure MaxBlockCount
308+ 0x00000000 ,
306309 0x00000000 ,
307310 0x00000000 ,
308311 0x00000000 ,
@@ -1205,19 +1208,21 @@ public void ShiftLeft(uint shift)
12051208 int readIndex = ( length - 1 ) ;
12061209 int writeIndex = readIndex + ( int ) ( blocksToShift ) ;
12071210
1208- uint remainingBitsInLastBlock = ( uint ) BitOperations . LeadingZeroCount ( _blocks [ readIndex ] ) ;
1209-
1210- if ( remainingBitsToShift > remainingBitsInLastBlock )
1211- {
1212- // We need an extra block for the partial shift
1213- writeIndex ++ ;
1214- }
1215-
1216- Debug . Assert ( unchecked ( ( uint ) ( writeIndex ) ) < MaxBlockCount ) ;
1217-
12181211 // Check if the shift is block aligned
12191212 if ( remainingBitsToShift == 0 )
12201213 {
1214+ Debug . Assert ( unchecked ( ( uint ) ( length ) ) < MaxBlockCount ) ;
1215+
1216+ if ( unchecked ( ( uint ) ( length ) ) >= MaxBlockCount )
1217+ {
1218+ // We shouldn't reach here, and the above assert will help flag this
1219+ // during testing, but we'll ensure that we return a safe value of
1220+ // zero in the case we end up overflowing in any way.
1221+
1222+ SetZero ( out this ) ;
1223+ return ;
1224+ }
1225+
12211226 while ( readIndex >= 0 )
12221227 {
12231228 _blocks [ writeIndex ] = _blocks [ readIndex ] ;
@@ -1232,6 +1237,21 @@ public void ShiftLeft(uint shift)
12321237 }
12331238 else
12341239 {
1240+ // We need an extra block for the partial shift
1241+
1242+ writeIndex ++ ;
1243+ Debug . Assert ( unchecked ( ( uint ) ( length ) ) < MaxBlockCount ) ;
1244+
1245+ if ( unchecked ( ( uint ) ( length ) ) >= MaxBlockCount )
1246+ {
1247+ // We shouldn't reach here, and the above assert will help flag this
1248+ // during testing, but we'll ensure that we return a safe value of
1249+ // zero in the case we end up overflowing in any way.
1250+
1251+ SetZero ( out this ) ;
1252+ return ;
1253+ }
1254+
12351255 // Set the length to hold the shifted blocks
12361256 _length = writeIndex + 1 ;
12371257
0 commit comments