@@ -32,7 +32,9 @@ internal unsafe ref struct BigInteger
32
32
private const int MaxBits = BitsForLongestBinaryMantissa + BitsForLongestDigitSequence + BitsPerBlock ;
33
33
34
34
private const int BitsPerBlock = sizeof ( int ) * 8 ;
35
- private const int MaxBlockCount = ( MaxBits + ( BitsPerBlock - 1 ) ) / BitsPerBlock ;
35
+
36
+ // We need one extra block to make our shift left algorithm significantly simpler
37
+ private const int MaxBlockCount = ( ( MaxBits + ( BitsPerBlock - 1 ) ) / BitsPerBlock ) + 1 ;
36
38
37
39
private static readonly uint [ ] s_Pow10UInt32Table = new uint [ ]
38
40
{
@@ -300,7 +302,8 @@ internal unsafe ref struct BigInteger
300
302
0xD9D61A05 ,
301
303
0x00000325 ,
302
304
303
- // 9 Trailing blocks to ensure MaxBlockCount
305
+ // 10 Trailing blocks to ensure MaxBlockCount
306
+ 0x00000000 ,
304
307
0x00000000 ,
305
308
0x00000000 ,
306
309
0x00000000 ,
@@ -1304,16 +1307,6 @@ public void ShiftLeft(uint shift)
1304
1307
int readIndex = ( length - 1 ) ;
1305
1308
int writeIndex = readIndex + ( int ) ( blocksToShift ) ;
1306
1309
1307
- uint remainingBitsInLastBlock = ( uint ) BitOperations . LeadingZeroCount ( _blocks [ readIndex ] ) ;
1308
-
1309
- if ( remainingBitsToShift > remainingBitsInLastBlock )
1310
- {
1311
- // We need an extra block for the partial shift
1312
- writeIndex ++ ;
1313
- }
1314
-
1315
- Debug . Assert ( unchecked ( ( uint ) ( writeIndex ) ) < MaxBlockCount ) ;
1316
-
1317
1310
if ( unchecked ( ( uint ) ( writeIndex ) ) >= MaxBlockCount )
1318
1311
{
1319
1312
// We shouldn't reach here, and the above assert will help flag this
@@ -1327,6 +1320,18 @@ public void ShiftLeft(uint shift)
1327
1320
// Check if the shift is block aligned
1328
1321
if ( remainingBitsToShift == 0 )
1329
1322
{
1323
+ Debug . Assert ( unchecked ( ( uint ) ( length ) ) < MaxBlockCount ) ;
1324
+
1325
+ if ( unchecked ( ( uint ) ( length ) ) >= MaxBlockCount )
1326
+ {
1327
+ // We shouldn't reach here, and the above assert will help flag this
1328
+ // during testing, but we'll ensure that we return a safe value of
1329
+ // zero in the case we end up overflowing in any way.
1330
+
1331
+ SetZero ( ) ;
1332
+ return ;
1333
+ }
1334
+
1330
1335
while ( readIndex >= 0 )
1331
1336
{
1332
1337
_blocks [ writeIndex ] = _blocks [ readIndex ] ;
@@ -1340,7 +1345,22 @@ public void ShiftLeft(uint shift)
1340
1345
Buffer . ZeroMemory ( ( byte * ) ( GetBlocksPointer ( ) ) , ( blocksToShift * sizeof ( uint ) ) ) ;
1341
1346
}
1342
1347
else
1343
- {
1348
+ {
1349
+ // We need an extra block for the partial shift
1350
+
1351
+ writeIndex ++ ;
1352
+ Debug . Assert ( unchecked ( ( uint ) ( length ) ) < MaxBlockCount ) ;
1353
+
1354
+ if ( unchecked ( ( uint ) ( length ) ) >= MaxBlockCount )
1355
+ {
1356
+ // We shouldn't reach here, and the above assert will help flag this
1357
+ // during testing, but we'll ensure that we return a safe value of
1358
+ // zero in the case we end up overflowing in any way.
1359
+
1360
+ SetZero ( ) ;
1361
+ return ;
1362
+ }
1363
+
1344
1364
// Set the length to hold the shifted blocks
1345
1365
_length = writeIndex + 1 ;
1346
1366
0 commit comments