summaryrefslogtreecommitdiff
path: root/vm_insnhelper.c
diff options
context:
space:
mode:
authorshyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-11-20 04:51:09 (GMT)
committershyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-11-20 04:51:09 (GMT)
commit0deee5c0aaf7a1b6a78bf4513fdd3a59475bfcf8 (patch)
treebc263c4743bd4b74204ea9b76edd6019c8635a8c /vm_insnhelper.c
parent0dfc5918ec19cb67d8a49915ad8ab177f56e4e73 (diff)
vm_insnhelper.c: recv -1 + 3 overflows
Here, recv can be INT2FIX(-1), which is 0xFFFF_FFFFul. INT2FIX(1) is 3ul. So `recv - 1 + INT2FIX(1)` is: recv 0xFFFF_FFFFul recv-1 0xFFFF_FFFEul (note: unsigned) recv-1+INT2FIX(1) 0x0000_0001ul Here is the overflow. Given recv is a Fixnum, it can never be 0xFFFF_FFFD. 0xFFFF_FFFF is the only value that can overflow this way, so special-casing this value should just suffice. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65828 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm_insnhelper.c')
-rw-r--r--vm_insnhelper.c36
1 files changed, 29 insertions, 7 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index ef4c938..04b0855 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -3763,17 +3763,39 @@ vm_opt_empty_p(VALUE recv)
}
static VALUE
+fix_succ(VALUE x)
+{
+ switch (x) {
+ case ~0UL:
+ /* 0xFFFF_FFFF == INT2FIX(-1)
+ * `-1.succ` is of course 0. */
+ return INT2FIX(0);
+ case RSHIFT(~0UL, 1):
+ /* 0x7FFF_FFFF == LONG2FIX(0x3FFF_FFFF)
+ * 0x3FFF_FFFF + 1 == 0x4000_0000, which is a Bignum. */
+ return rb_uint2big(1UL << (SIZEOF_LONG * CHAR_BIT - 2));
+ default:
+ /* LONG2FIX(FIX2LONG(x)+FIX2LONG(y))
+ * == ((lx*2+1)/2 + (ly*2+1)/2)*2+1
+ * == lx*2 + ly*2 + 1
+ * == (lx*2+1) + (ly*2+1) - 1
+ * == x + y - 1
+ *
+ * Here, if we put y := INT2FIX(1):
+ *
+ * == x + INT2FIX(1) - 1
+ * == x + 2 .
+ */
+ return x + 2;
+ }
+}
+
+static VALUE
vm_opt_succ(VALUE recv)
{
if (FIXNUM_P(recv) &&
BASIC_OP_UNREDEFINED_P(BOP_SUCC, INTEGER_REDEFINED_OP_FLAG)) {
- /* fixnum + INT2FIX(1) */
- if (recv == LONG2FIX(FIXNUM_MAX)) {
- return LONG2NUM(FIXNUM_MAX + 1);
- }
- else {
- return recv - 1 + INT2FIX(1);
- }
+ return fix_succ(recv);
}
else if (SPECIAL_CONST_P(recv)) {
return Qundef;