Skip to content

Commit

Permalink
Correctly detect+handle overflow in mp_get_int64
Browse files Browse the repository at this point in the history
Handles the fact that for 64-bit 2's complement numbers the maximum
positive value is 2**63 - 1, but the maximum negative value is 2**63.

Uses the mp_get_long_long now available with the newer version of
libtommath. Also, instead of counting the bits every time, only do it
during the too-large-value error path.
  • Loading branch information
MasterDuke17 committed Mar 24, 2017
1 parent a844814 commit 84a730f
Showing 1 changed file with 16 additions and 19 deletions.
35 changes: 16 additions & 19 deletions src/6model/reprs/P6bigint.c
Expand Up @@ -4,30 +4,27 @@
#define MIN(x,y) ((x)<(y)?(x):(y))
#endif

/* A forced 64-bit version of mp_get_long, since on some platforms long is
* not all that long. */
static MVMuint64 mp_get_int64(MVMThreadContext *tc, mp_int * a) {
int i, bits;
/* Handles both int and uint cases. */
static MVMuint64 mp_get_int64(MVMThreadContext *tc, mp_int * a, int sign) {
MVMuint64 res;
MVMuint64 signed_max = 9223372036854775807ULL;

if (a->used == 0) {
return 0;
return 0;
}

bits = mp_count_bits(a);
if (bits > 64) {
MVM_exception_throw_adhoc(tc, "Cannot unbox %d bit wide bigint into native integer", bits);
/* For 64-bit 2's complement numbers the positive max is 2**63-1
* but the negative max is 2**63. */
if (sign && MP_NEG == SIGN(a)) {
++signed_max;
}

/* get number of digits of the lsb we have to read */
i = MIN(a->used,(int)((sizeof(MVMuint64)*CHAR_BIT+DIGIT_BIT-1)/DIGIT_BIT))-1;

/* get most significant digit of result */
res = DIGIT(a,i);

while (--i >= 0) {
res = (res << DIGIT_BIT) | DIGIT(a,i);
res = mp_get_long_long(a);
if (res == 0 || (sign && res > signed_max)) {
/* The mp_int was either so big it overflowed a MVMuint64 or was bigger than a signed result could be. */
MVM_exception_throw_adhoc(tc, "Cannot unbox %d bit wide bigint into native integer", mp_count_bits(a));
}

return res;
}

Expand Down Expand Up @@ -92,10 +89,10 @@ static MVMint64 get_int(MVMThreadContext *tc, MVMSTable *st, MVMObject *root, vo
if (MVM_BIGINT_IS_BIG(body)) {
mp_int *i = body->u.bigint;
if (MP_NEG == SIGN(i)) {
return -mp_get_int64(tc, i);
return -mp_get_int64(tc, i, 1);
}
else {
return mp_get_int64(tc, i);
return mp_get_int64(tc, i, 1);
}
}
else {
Expand Down Expand Up @@ -123,7 +120,7 @@ static MVMuint64 get_uint(MVMThreadContext *tc, MVMSTable *st, MVMObject *root,
if (MP_NEG == SIGN(i))
MVM_exception_throw_adhoc(tc, "Cannot unbox negative bigint into native unsigned integer");
else
return mp_get_int64(tc, i);
return mp_get_int64(tc, i, 0);
}
else {
return body->u.smallint.value;
Expand Down

0 comments on commit 84a730f

Please sign in to comment.