diff options
Diffstat (limited to 'bignum.c')
-rw-r--r-- | bignum.c | 37 |
1 files changed, 25 insertions, 12 deletions
@@ -852,7 +852,6 @@ integer_unpack_push_bits(int data, int numbits, BDIGIT_DBL *ddp, int *numbits_in VALUE rb_integer_unpack(int sign, const void *words, size_t numwords, size_t wordsize, size_t nails, int flags) { - VALUE num_bits, num_bdigits; VALUE result; const unsigned char *buf = words; @@ -877,20 +876,34 @@ rb_integer_unpack(int sign, const void *words, size_t numwords, size_t wordsize, if (sign != 1 && sign != 0 && sign != -1) rb_raise(rb_eArgError, "unexpected sign: %d", sign); - /* num_bits = (wordsize * CHAR_BIT - nails) * count */ - num_bits = SIZET2NUM(wordsize); - num_bits = rb_funcall(num_bits, '*', 1, LONG2FIX(CHAR_BIT)); - num_bits = rb_funcall(num_bits, '-', 1, SIZET2NUM(nails)); - num_bits = rb_funcall(num_bits, '*', 1, SIZET2NUM(numwords)); + if (numwords <= (SIZE_MAX - (SIZEOF_BDIGITS*CHAR_BIT-1)) / CHAR_BIT / wordsize) { + size_t num_bits, num_bdigits; + num_bits = (wordsize * CHAR_BIT - nails) * numwords; + if (num_bits == 0) + return LONG2FIX(0); + num_bdigits = (num_bits + SIZEOF_BDIGITS*CHAR_BIT - 1) / (SIZEOF_BDIGITS*CHAR_BIT); + if (LONG_MAX < num_bdigits) + rb_raise(rb_eArgError, "too big to unpack as an integer"); + result = bignew((long)num_bdigits, 0 <= sign); + } + else { + VALUE num_bits, num_bdigits; - if (num_bits == LONG2FIX(0)) - return LONG2FIX(0); + /* num_bits = (wordsize * CHAR_BIT - nails) * numwords */ + num_bits = SIZET2NUM(wordsize); + num_bits = rb_funcall(num_bits, '*', 1, LONG2FIX(CHAR_BIT)); + num_bits = rb_funcall(num_bits, '-', 1, SIZET2NUM(nails)); + num_bits = rb_funcall(num_bits, '*', 1, SIZET2NUM(numwords)); - /* num_bdigits = (num_bits + SIZEOF_BDIGITS*CHAR_BIT - 1) / (SIZEOF_BDIGITS*CHAR_BIT) */ - num_bdigits = rb_funcall(num_bits, '+', 1, LONG2FIX(SIZEOF_BDIGITS*CHAR_BIT-1)); - num_bdigits = rb_funcall(num_bdigits, '/', 1, LONG2FIX(SIZEOF_BDIGITS*CHAR_BIT)); + if (num_bits == LONG2FIX(0)) + return LONG2FIX(0); - result = bignew(NUM2LONG(num_bdigits), 0 <= sign); + /* num_bdigits = (num_bits + SIZEOF_BDIGITS*CHAR_BIT - 1) / (SIZEOF_BDIGITS*CHAR_BIT) */ + num_bdigits = rb_funcall(num_bits, '+', 1, LONG2FIX(SIZEOF_BDIGITS*CHAR_BIT-1)); + num_bdigits = rb_funcall(num_bdigits, '/', 1, LONG2FIX(SIZEOF_BDIGITS*CHAR_BIT)); + + result = bignew(NUM2LONG(num_bdigits), 0 <= sign); + } dp = BDIGITS(result); de = dp + RBIGNUM_LEN(result); |