Skip to content

Commit 7fb8174

Browse files
smowtonpeterschrammel
authored andcommitted
Fix arithmetic shift operators
to_ulong() will negate a negative number, rather than returning its two's complement representation as an unsigned type as we might reasonably suppose. Instead use to_long() everywhere to preserve the bitwise representation and then use sign-bit filling to make sure the value is correctly re-encoded as mp_integer.
1 parent d81dd75 commit 7fb8174

File tree

1 file changed

+26
-12
lines changed

1 file changed

+26
-12
lines changed

src/util/mp_arith.cpp

+26-12
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ Author: Daniel Kroening, [email protected]
1818
#include "arith_tools.h"
1919

2020

21-
typedef BigInt::ullong_t ullong_t;
21+
typedef BigInt::ullong_t ullong_t; // NOLINT(readability/identifiers)
22+
typedef BigInt::llong_t llong_t; // NOLINT(readability/identifiers)
2223

2324
/*******************************************************************\
2425
@@ -432,8 +433,12 @@ mp_integer arith_left_shift(
432433
if(shift>true_size && a!=mp_integer(0))
433434
throw "shift value out of range";
434435

435-
ullong_t result=a.to_ulong()<<shift;
436-
return result;
436+
llong_t result=a.to_long()<<shift;
437+
llong_t mask=
438+
true_size<(sizeof(llong_t)*8) ?
439+
(1L<<true_size)-1 :
440+
-1;
441+
return result&mask;
437442
}
438443

439444
/*******************************************************************\
@@ -456,14 +461,14 @@ mp_integer arith_right_shift(
456461
const mp_integer &b,
457462
std::size_t true_size)
458463
{
459-
ullong_t number=a.to_ulong();
464+
llong_t number=a.to_long();
460465
ullong_t shift=b.to_ulong();
461466
if(shift>true_size)
462467
throw "shift value out of range";
463468

464-
ullong_t sign=(1<<(true_size-1))&number;
465-
ullong_t pad=(sign==0) ? 0 : ~((1<<(true_size-shift))-1);
466-
ullong_t result=(number>>shift)|pad;
469+
llong_t sign=(1<<(true_size-1))&number;
470+
llong_t pad=(sign==0) ? 0 : ~((1<<(true_size-shift))-1);
471+
llong_t result=(number >> shift)|pad;
467472
return result;
468473
}
469474

@@ -490,8 +495,17 @@ mp_integer logic_left_shift(
490495
ullong_t shift=b.to_ulong();
491496
if(shift>true_size && a!=mp_integer(0))
492497
throw "shift value out of range";
493-
494-
ullong_t result=a.to_ulong()<<shift;
498+
llong_t result=a.to_long()<<shift;
499+
if(true_size<(sizeof(llong_t)*8))
500+
{
501+
llong_t sign=(1L<<(true_size-1))&result;
502+
llong_t mask=(1L<<true_size)-1;
503+
// Sign-fill out-of-range bits:
504+
if(sign==0)
505+
result&=mask;
506+
else
507+
result|=~mask;
508+
}
495509
return result;
496510
}
497511

@@ -519,7 +533,7 @@ mp_integer logic_right_shift(
519533
if(shift>true_size)
520534
throw "shift value out of range";
521535

522-
ullong_t result=a.to_ulong()>>shift;
536+
ullong_t result=((ullong_t)a.to_long()) >> shift;
523537
return result;
524538
}
525539

@@ -550,7 +564,7 @@ mp_integer rotate_right(
550564

551565
ullong_t revShift=true_size-shift;
552566
ullong_t filter=1<<(true_size-1);
553-
ullong_t result=(number>>shift)|((number<<revShift)&filter);
567+
ullong_t result=(number >> shift)|((number<<revShift)&filter);
554568
return result;
555569
}
556570

@@ -581,6 +595,6 @@ mp_integer rotate_left(
581595

582596
ullong_t revShift=true_size-shift;
583597
ullong_t filter=1<<(true_size-1);
584-
ullong_t result=((number<<shift)&filter)|((number&filter)>>revShift);
598+
ullong_t result=((number<<shift)&filter)|((number&filter) >> revShift);
585599
return result;
586600
}

0 commit comments

Comments
 (0)