@@ -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 ,
@@ -1206,19 +1209,21 @@ public void ShiftLeft(uint shift)
1206
1209
int readIndex = ( length - 1 ) ;
1207
1210
int writeIndex = readIndex + ( int ) ( blocksToShift ) ;
1208
1211
1209
- uint remainingBitsInLastBlock = ( uint ) BitOperations . LeadingZeroCount ( _blocks [ readIndex ] ) ;
1210
-
1211
- if ( remainingBitsToShift > remainingBitsInLastBlock )
1212
- {
1213
- // We need an extra block for the partial shift
1214
- writeIndex ++ ;
1215
- }
1216
-
1217
- Debug . Assert ( unchecked ( ( uint ) ( writeIndex ) ) < MaxBlockCount ) ;
1218
-
1219
1212
// Check if the shift is block aligned
1220
1213
if ( remainingBitsToShift == 0 )
1221
1214
{
1215
+ Debug . Assert ( unchecked ( ( uint ) ( length ) ) < MaxBlockCount ) ;
1216
+
1217
+ if ( unchecked ( ( uint ) ( length ) ) >= MaxBlockCount )
1218
+ {
1219
+ // We shouldn't reach here, and the above assert will help flag this
1220
+ // during testing, but we'll ensure that we return a safe value of
1221
+ // zero in the case we end up overflowing in any way.
1222
+
1223
+ SetZero ( out this ) ;
1224
+ return ;
1225
+ }
1226
+
1222
1227
while ( readIndex >= 0 )
1223
1228
{
1224
1229
_blocks [ writeIndex ] = _blocks [ readIndex ] ;
@@ -1233,6 +1238,21 @@ public void ShiftLeft(uint shift)
1233
1238
}
1234
1239
else
1235
1240
{
1241
+ // We need an extra block for the partial shift
1242
+
1243
+ writeIndex ++ ;
1244
+ Debug . Assert ( unchecked ( ( uint ) ( length ) ) < MaxBlockCount ) ;
1245
+
1246
+ if ( unchecked ( ( uint ) ( length ) ) >= MaxBlockCount )
1247
+ {
1248
+ // We shouldn't reach here, and the above assert will help flag this
1249
+ // during testing, but we'll ensure that we return a safe value of
1250
+ // zero in the case we end up overflowing in any way.
1251
+
1252
+ SetZero ( out this ) ;
1253
+ return ;
1254
+ }
1255
+
1236
1256
// Set the length to hold the shifted blocks
1237
1257
_length = writeIndex + 1 ;
1238
1258
0 commit comments