@@ -31,7 +31,9 @@ internal unsafe ref struct BigInteger
31
31
private const int MaxBits = BitsForLongestBinaryMantissa + BitsForLongestDigitSequence + BitsPerBlock ;
32
32
33
33
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 ;
35
37
36
38
private static readonly uint [ ] s_Pow10UInt32Table = new uint [ ]
37
39
{
@@ -302,7 +304,8 @@ internal unsafe ref struct BigInteger
302
304
0xD9D61A05 ,
303
305
0x00000325 ,
304
306
305
- // 9 Trailing blocks to ensure MaxBlockCount
307
+ // 10 Trailing blocks to ensure MaxBlockCount
308
+ 0x00000000 ,
306
309
0x00000000 ,
307
310
0x00000000 ,
308
311
0x00000000 ,
@@ -1205,19 +1208,21 @@ public void ShiftLeft(uint shift)
1205
1208
int readIndex = ( length - 1 ) ;
1206
1209
int writeIndex = readIndex + ( int ) ( blocksToShift ) ;
1207
1210
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
-
1218
1211
// Check if the shift is block aligned
1219
1212
if ( remainingBitsToShift == 0 )
1220
1213
{
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
+
1221
1226
while ( readIndex >= 0 )
1222
1227
{
1223
1228
_blocks [ writeIndex ] = _blocks [ readIndex ] ;
@@ -1232,6 +1237,21 @@ public void ShiftLeft(uint shift)
1232
1237
}
1233
1238
else
1234
1239
{
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
+
1235
1255
// Set the length to hold the shifted blocks
1236
1256
_length = writeIndex + 1 ;
1237
1257
0 commit comments