summaryrefslogtreecommitdiff
path: root/bignum.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-06-08 07:40:03 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-06-08 07:40:03 +0000
commitd35616e69456305c78fd72c35aaf6a1beefc49f1 (patch)
tree38fe2102379f43b0a946d96235db19e07b27a638 /bignum.c
parent8a1609040e959ffb370c121840cf1fdfb144616a (diff)
* bignum.c (rb_integer_unpack): Don't use rb_funcall if possible.
* random.c: Use uint32_t for elements of seed. (make_seed_value): Use rb_integer_unpack. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41169 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'bignum.c')
-rw-r--r--bignum.c37
1 files changed, 25 insertions, 12 deletions
diff --git a/bignum.c b/bignum.c
index 1c92117669..9f6e1b9fc6 100644
--- a/bignum.c
+++ b/bignum.c
@@ -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);