ADDITIONAL SYSTEM INFORMATION :
I got it on windows, but probably others too, not 100% sure.
A DESCRIPTION OF THE PROBLEM :
If you write an invalid value into an array with Unsafe.putObjectVolatile then you can use Unsafe.getObjectVolatile to read it out, before JIT happens. After that the value is no longer the same.
REGRESSION : Last worked in version 8
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the program provided.
ACTUAL -
It prints out:
Start
value: Test:0
value: java.lang.Object@5caf905d
Test: 10000 vs 0
fail: java.lang.Object@5caf905d vs java.lang.Object@5caf905d vs java.lang.Object@5caf905d comps: false vs false
value: java.lang.Object@5caf905d vs true
Done: 10000 vs 1
The diff branch should newer be reached on the program. But is reached after jit goes over the program. As you can see on the fail line the comparison writes out "false", but in the outer non-jit method the results is still true as before.
I got the same results also on older JDK version (including 8) but as the behaviour before and after jit is different I decided to report it.
You can also probably argue that unsafe should not be used, but maybe the JIT issue is not related to unsafe directly and shows some underlying issue in JIT? And maybe the same issue can happen from "legal" JDK core own usages usages..
---------- BEGIN SOURCE ----------
package autotest;
import java.lang.reflect.Field;
import java.util.Arrays;
public class Test {
private static final Object MARKER = new Object();
private static final Test[] testArray = new Test[] { new Test(0), new Test(1), new Test(2), new Test(3), new Test(4), new Test(5), new Test(6) };
private static sun.misc.Unsafe unsafe;
private static int ABASE;
private final int i;
public Test() {
this(-1);
}
public Test(int i) {
this.i = i;
}
public static void main(String[]... args) throws Throwable {
new Test().test();
}
public void test() throws Throwable {
System.out.println("Start");
try {
Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
unsafe = (sun.misc.Unsafe) f.get(null);
ABASE = unsafe.arrayBaseOffset(Object[].class);
// public void putObjectVolatile(Object o, long offset, Object x) {
// public Object getObjectVolatile(Object o, long offset) {
System.out.println("value: " + unsafe.getObjectVolatile(testArray, ABASE));
// Abuse unsafe to set a value
unsafe.putObjectVolatile(testArray, ABASE, MARKER);
System.out.println("value: " + unsafe.getObjectVolatile(testArray, ABASE));
outer: for (int z = 0; z < 10; z++) {
for (int i = 0; i < 10000; i++) {
if (doWork()) {
break outer;
}
}
System.out.println("Test: " + same + " vs " + diff);
}
System.out.println("value: " + unsafe.getObjectVolatile(testArray, ABASE) + " vs " + (unsafe.getObjectVolatile(testArray, ABASE) == MARKER));
}
catch (Exception ex) {
throw new Error(ex);
}
System.out.println("Done: " + same + " vs " + diff);
}
int same = 0;
int diff = 0;
public boolean doWork() {
// After JIT this one fails..
Object o = unsafe.getObjectVolatile(testArray, ABASE);
if (o == MARKER) {
same++;
return false;
}
else {
diff++;
System.out.println("fail: " + unsafe.getObjectVolatile(testArray, ABASE) + " vs " + o + " vs " + MARKER + " comps: " + (o == MARKER) + " vs " + (unsafe.getObjectVolatile(testArray, ABASE) == MARKER));
return true;
}
}
public String toString() {
return "Test:" + i;
}
}
---------- END SOURCE ----------
FREQUENCY : always
I got it on windows, but probably others too, not 100% sure.
A DESCRIPTION OF THE PROBLEM :
If you write an invalid value into an array with Unsafe.putObjectVolatile then you can use Unsafe.getObjectVolatile to read it out, before JIT happens. After that the value is no longer the same.
REGRESSION : Last worked in version 8
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the program provided.
ACTUAL -
It prints out:
Start
value: Test:0
value: java.lang.Object@5caf905d
Test: 10000 vs 0
fail: java.lang.Object@5caf905d vs java.lang.Object@5caf905d vs java.lang.Object@5caf905d comps: false vs false
value: java.lang.Object@5caf905d vs true
Done: 10000 vs 1
The diff branch should newer be reached on the program. But is reached after jit goes over the program. As you can see on the fail line the comparison writes out "false", but in the outer non-jit method the results is still true as before.
I got the same results also on older JDK version (including 8) but as the behaviour before and after jit is different I decided to report it.
You can also probably argue that unsafe should not be used, but maybe the JIT issue is not related to unsafe directly and shows some underlying issue in JIT? And maybe the same issue can happen from "legal" JDK core own usages usages..
---------- BEGIN SOURCE ----------
package autotest;
import java.lang.reflect.Field;
import java.util.Arrays;
public class Test {
private static final Object MARKER = new Object();
private static final Test[] testArray = new Test[] { new Test(0), new Test(1), new Test(2), new Test(3), new Test(4), new Test(5), new Test(6) };
private static sun.misc.Unsafe unsafe;
private static int ABASE;
private final int i;
public Test() {
this(-1);
}
public Test(int i) {
this.i = i;
}
public static void main(String[]... args) throws Throwable {
new Test().test();
}
public void test() throws Throwable {
System.out.println("Start");
try {
Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
unsafe = (sun.misc.Unsafe) f.get(null);
ABASE = unsafe.arrayBaseOffset(Object[].class);
// public void putObjectVolatile(Object o, long offset, Object x) {
// public Object getObjectVolatile(Object o, long offset) {
System.out.println("value: " + unsafe.getObjectVolatile(testArray, ABASE));
// Abuse unsafe to set a value
unsafe.putObjectVolatile(testArray, ABASE, MARKER);
System.out.println("value: " + unsafe.getObjectVolatile(testArray, ABASE));
outer: for (int z = 0; z < 10; z++) {
for (int i = 0; i < 10000; i++) {
if (doWork()) {
break outer;
}
}
System.out.println("Test: " + same + " vs " + diff);
}
System.out.println("value: " + unsafe.getObjectVolatile(testArray, ABASE) + " vs " + (unsafe.getObjectVolatile(testArray, ABASE) == MARKER));
}
catch (Exception ex) {
throw new Error(ex);
}
System.out.println("Done: " + same + " vs " + diff);
}
int same = 0;
int diff = 0;
public boolean doWork() {
// After JIT this one fails..
Object o = unsafe.getObjectVolatile(testArray, ABASE);
if (o == MARKER) {
same++;
return false;
}
else {
diff++;
System.out.println("fail: " + unsafe.getObjectVolatile(testArray, ABASE) + " vs " + o + " vs " + MARKER + " comps: " + (o == MARKER) + " vs " + (unsafe.getObjectVolatile(testArray, ABASE) == MARKER));
return true;
}
}
public String toString() {
return "Test:" + i;
}
}
---------- END SOURCE ----------
FREQUENCY : always