JDK-6357214 : Hotspot server compiler gets integer comparison wrong
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 5.0,6u6
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux,solaris_10
  • CPU: x86,sparc
  • Submitted: 2005-11-30
  • Updated: 2010-04-02
  • Resolved: 2009-07-31
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_05"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_05-b05)
Java HotSpot(TM) Client VM (build 1.5.0_05-b05, mixed mode)

1.5.0_05, also 1.4.2_10 and 1.3.1_16.

FULL OS VERSION :
Solaris 10

A DESCRIPTION OF THE PROBLEM :
In the example code, the test "if (i>limit) {" in method create() gives the wrong result. It indicates that i > limit when i is zero and limit is Integer.MAX_VALUE.

Look

THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: No

THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the attached demo code as

javac SCPF.java

Then run as

java -server -DshowAll=ffo -DeventID=444 SCPF



EXPECTED VERSUS ACTUAL BEHAVIOR :
SHOULD DO:
The test should run forever printing out line after line

DOES:
The test stops after a couple of iterations. If you run with -Xint the test runs as expected.

The problem appears to be with the way the optimizer chooses to rewrite the test. In this case, the value of limit is going to be Integer.MAX_VALUE.

Looking at the generated SPARC code, the test has been re-written as:

if ((i+1) >= (limit+2))

And (limit+2) is calculated in advance by the simple expedient of adding 2 to Integer.MAX_VALUE. This produces the value 0x80000001, which of course is a big negative number, so the test

if (0 > 0x7FFFFFFF)

comes out TRUE!
REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
class MyResult {
        public boolean next() {
                return true;
        }

        public String getString(String in) {
                if (in.equals("id"))
                        return "idFoo";
                if (in.equals("contentKey"))
                        return "ckFoo";
                return "Foo";
        }

        public int getInt(String in) {
                if (in.equals("processingComplete"))
                        return 0;
                return 1;
        }

        public byte[] getBytes(String in) {
                byte[] arr = null;
                if (in.equals("content")) {
                        arr = new byte[65536];
                        byte j = 32;
                        for (int i=0; i<65536; i++) {
                                arr[i] = j;
                                if (++j == 127)
                                        j=32;
                        }
                }
                return arr;
        }
}

public class SCPF {
        public static volatile boolean bollocks = true;
    public String create(String context) throws Exception {

        //
        // Extract HTTP parameters
        //

        boolean showAll = System.getProperty("showAll") != null;
          String eventID = System.getProperty("eventID");
          String eventContentKey = System.getProperty("cKey");
        //
        // Build ContentStaging query based on eventID or eventContentKey
        //

        String sql = "select id, processingComplete, contentKey, content "
                   + "from   ContentStaging cs, ContentStagingKey csk "
                   + "where  cs.eventContentKey = csk.eventContentKey ";

        if (eventID != null) {
            sql += "and id = " + eventID;
        }
        else if (eventContentKey != null) {
            sql += "and cs.eventContentKey = '"
                +  eventContentKey
                +  "' having id = max(id)";
        }
        else {
            throw new Exception("Need eventID or eventContentKey");
        }

        //
        // This factory builds a static panel, there is no JSP
        //

        StringBuffer html = new StringBuffer();

        try {

                MyResult result = new MyResult();
            if (result.next()) {

                eventID = result.getString("id");
                int processingComplete = result.getInt("processingComplete");
                String contentKey = result.getString("contentKey");
                byte[] bytes = result.getBytes("content");

                //
                // Print content status and associated controls
                //

                html.append("<br/><font class=\"small\">");
                html.append("Status: ");
                switch (processingComplete) {
                    case  0 :
                    case  1 : html.append("PENDING"); break;
                    case  2 : html.append(contentKey); break;
                    case  3 : html.append(eventID); break;
                    default : html.append("UNKNONW");
                }
                html.append("</font><br/>");

                //
                // Print at most 20Kb of content unless "showAll" is set
                //

                int limit = showAll ? Integer.MAX_VALUE : 1024 * 20;
                System.out.println(limit);
                html.append("<pre>");
                for (int i = 0; bytes != null && i < bytes.length; i++) {
                    char c = (char) bytes[i];
                    switch (c) {
                        case '<' : html.append("&lt;");  break;
                        case '>' : html.append("&gt;");  break;
                        case '&' : html.append("&amp;"); break;
                        default  : html.append(c);
                    }

                    if (i > limit) {
                        while (bollocks);
                        // System.out.println("i is " + i);
                        // System.out.println("limit is " + limit);
                        html.append("...\n</pre>");
                        html.append(eventID);
                        html.append("<pre>");
                        break;
                    }
                }
                html.append("</pre>");
            }
        }
        catch (Exception exception) {
            throw exception;
        }
        finally {
            html.append("Oof!!");
        }
        String ret = html.toString();
        System.out.println("Returning string length = "+ ret.length());
        return ret;
    }

    public static void main(String[] args) throws Exception {
                int length=0;

                while (true) {
                        length = new SCPF().create("boo").length();
                        System.out.println(length);
                }
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Tweak the code to work around the dodgy optimizer

Comments
EVALUATION This is the same problem as 5091921: Sign flip issues in loop optimizer. So I close this one as a duplicate and work on 5091921
31-07-2009

EVALUATION Seems to be the same bug as 6186134.
31-01-2008