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("<"); break;
case '>' : html.append(">"); break;
case '&' : html.append("&"); 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
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("<"); break;
case '>' : html.append(">"); break;
case '&' : html.append("&"); 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
- duplicates
-
JDK-6753639 Strange optimisation in for loop with cyclic integer condition
-
- Closed
-
-
JDK-5091921 Sign flip issues in loop optimizer
-
- Closed
-
- relates to
-
JDK-5094936 Compiler generates wrong results (wrong loop optimization)
-
- Closed
-
-
JDK-6196102 Integer seems to be greater than Integer.MAX_VALUE
-
- Closed
-
-
JDK-6186134 Server virtual machine produces/exeutes incorrect code.
-
- Closed
-