JRuby (please use github issues at http://bugs.jruby.org)
  1. JRuby (please use github issues at http://bugs.jruby.org)
  2. JRUBY-6779

Strange behaviour of some Integer Ranges with Range#each - maybe an integer overflow problem?

    Details

    • Type: Bug Bug
    • Status: Resolved Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: JRuby 1.7.0.pre1
    • Fix Version/s: JRuby 1.7.0.pre2
    • Component/s: Application Error
    • Labels:
      None
    • Environment:
      I'm running Microsoft Windows Vista with Java Client VM 1.6.0_14, but I think the problem is likely to independent of the platform.
    • Number of attachments :
      0

      Description

      This seems to be a problem in 1.7.0.preview1 and in 1.6.7; I haven't tried it in other JRuby versions, but I suspect it will be a problem in other JRuby versions.

      In JIRB or run as a JRuby program:

        def rr(rng)
          puts
          puts "demonstrating (" + rng.inspect + ").each problem:"
          indx = -1  # use indx to prevent an almost infinite loop
          rng.each do |v|
            indx += 1
            puts "  each indx= #{indx.inspect}, v= #{v.inspect}"
            break  if indx >= 5
          end
        end
        vv = 2**63
        rr(vv - 3 ... vv + 0)  # (1) at indx == 3 has integer overflow
        rr(vv - 3 ..  vv + 0)  # (2) at indx == 3 has integer overflow
        rr(vv - 3 ... vv - 1)  # (3) prints out expected "each" values
        rr(vv - 3 ..  vv - 1)  # (4) doesn't print out any "each" values
      

      In JRUBY-6612 I reported an integer overflow problem in RubyFixnum.java in
      public IRubyObject op_mul
      and also gave examples of some strange behaviour of Range#each
      with integer values near the maximum Fixnum value.

      The reported integer overflow problem seems to have been fixed in
      JRuby 1.7.0.preview1
      but I still seem to be getting this sometimes strange behaviour of Range#each.

      I've put below extracts from RubyRange.java: it seems that the problem may arise in "private void rangeEach".

      I suspect that the problems of examples (1) and (2) above might be caused (at least partly) by a problem with Integer#succ which I've reported here:
      JRUBY-6778 Possible long integer overflow bug in Integer#succ in RubyInteger.java
      So fixing that Integer#succ problem may fix (1) and (2).

      But it's not clear to me from the RubyRange.java code why the exclusive range in (3) works but the inclusive range in (4) doesn't work, and I don't have a sufficient understanding of the interaction between the underlying Java code for various JRuby classes to see what is the cause of the problem.

      ***** extracts from RubyRange.java  1.7.0.preview1  from line 346
      
          private IRubyObject rangeLt(ThreadContext context, IRubyObject a, IRubyObject b) {
              IRubyObject result = invokedynamic(context, a, OP_CMP, b);
              if (result.isNil()) return null;
              return RubyComparable.cmpint(context, result, a, b) < 0 ? getRuntime().getTrue() : null;
          }
      
          private IRubyObject rangeLe(ThreadContext context, IRubyObject a, IRubyObject b) {
              IRubyObject result = invokedynamic(context, a, OP_CMP, b);
              if (result.isNil()) return null;
              int c = RubyComparable.cmpint(context, result, a, b);
              if (c == 0) return RubyFixnum.zero(getRuntime());
              return c < 0 ? getRuntime().getTrue() : null;
          }    
      
          private void rangeEach(ThreadContext context, RangeCallBack callback) {
              IRubyObject v = begin;
              if (isExclusive) {
                  while (rangeLt(context, v, end) != null) {
                      callback.call(context, v);
                      v = v.callMethod(context, "succ");
                  }
              } else {
                  IRubyObject c;
                  while ((c = rangeLe(context, v, end)) != null && c.isTrue()) {
                      callback.call(context, v);
                      if (c == RubyFixnum.zero(getRuntime())) break;
                      v = v.callMethod(context, "succ");
                  }
              }
          }
      

        Activity

        Hide
        Charles Oliver Nutter added a comment -

        With the fix for JRUBY-6612, we appear to match MRI output for this one too.

        Show
        Charles Oliver Nutter added a comment - With the fix for JRUBY-6612 , we appear to match MRI output for this one too.
        Hide
        Charles Oliver Nutter added a comment -

        Additional fixes:

        commit ee963e52200617634eb11d9ffbf984b956f7fb21
        Author: Charles Oliver Nutter <headius@headius.com>
        Date:   Thu Nov 8 13:44:42 2012 -0600
        
            Fix JRUBY-6612, JRUBY-6777, JRUBY-6778, JRUBY-6779, JRUBY-6790
            
            [JRUBY-6612] some problems with JRuby seeming to not detect Java Long arithmetic overflows
            [JRUBY-6777] RubyFixnum.java - two methods fail to detect some long integer overflows
            [JRUBY-6778] Possible long integer overflow bug in Integer#succ in RubyInteger.java
            [JRUBY-6779] Strange behaviour of some Integer Ranges with Range#each - maybe an integer overflow problem?
            [JRUBY-6790] Possible long integer overflow in fixnumStep in RubyNumeric.java
            
            Patches by Colin Bartlett. Thank you!
        
        :100644 100644 93f83c8... 109b856... M	src/org/jruby/RubyInteger.java
        :100644 100644 b631a40... 7ecf098... M	src/org/jruby/RubyNumeric.java
        :100644 100644 3ed0b55... d15c2ed... M	src/org/jruby/RubyRange.java
        
        Show
        Charles Oliver Nutter added a comment - Additional fixes: commit ee963e52200617634eb11d9ffbf984b956f7fb21 Author: Charles Oliver Nutter <headius@headius.com> Date: Thu Nov 8 13:44:42 2012 -0600 Fix JRUBY-6612, JRUBY-6777, JRUBY-6778, JRUBY-6779, JRUBY-6790 [JRUBY-6612] some problems with JRuby seeming to not detect Java Long arithmetic overflows [JRUBY-6777] RubyFixnum.java - two methods fail to detect some long integer overflows [JRUBY-6778] Possible long integer overflow bug in Integer#succ in RubyInteger.java [JRUBY-6779] Strange behaviour of some Integer Ranges with Range#each - maybe an integer overflow problem? [JRUBY-6790] Possible long integer overflow in fixnumStep in RubyNumeric.java Patches by Colin Bartlett. Thank you! :100644 100644 93f83c8... 109b856... M src/org/jruby/RubyInteger.java :100644 100644 b631a40... 7ecf098... M src/org/jruby/RubyNumeric.java :100644 100644 3ed0b55... d15c2ed... M src/org/jruby/RubyRange.java

          People

          • Assignee:
            Charles Oliver Nutter
            Reporter:
            Colin Bartlett
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: