[9] RFR(S): 8076445: Array accesses using sun.misc.Unsafe cause data corruption or SIGSEGV
Zoltán Majó
zoltan.majo at oracle.com
Fri Apr 17 14:38:54 UTC 2015
Hi,
please review the following patch.
Bug: https://bugs.openjdk.java.net/browse/JDK-8076445
Problem: The errors listed in the bug description appear because the C1
compiler can generate incorrect memory addressing if unsafe intrinsics
are inlined.
The problem appears if a Unsafe.putInt is followed by an Unsafe.getInt
to the same location, for example if the following Java code is compiled
(some details omitted):
1: for (long index = 0; index < arraySize; index++) {
2: long offset = pointer + (index * SIZE_OF_INT_IN_BYTES);
3: unsafe.putInt(offset, (int)index);
4: int readback = unsafe.getInt(offset);
5: }
Here is the C1 compiler's HIR for lines 3 and 4:
_p__bci__use__tid__result____instruction________________________________________
(HIR)
...
. 20 1 a23 [R194|L] a17._104 (L) unsafe
25 1 i24 [R195|I] l2i(l6)
. 26 0 a25 null_check(a23)
. 26 0 v26 UnsafePutRaw.(base l18, index l6,
log2_scale 2, value i24)
. 29 1 a28 [R196|L] a17._104 (L) unsafe
. 33 0 a29 null_check(a28)
. 33 1 i30 [R197|I] UnsafeGetRaw.(base l18, index l6,
log2_scale 2)
...
On the HIR level, both UnsafePutRaw and UnsafeGetRaw use the same (and
correct) base, index, and scale. On the LIR level, however, the
following is generated:
_nr___instruction_______________________________________________________________
(LIR)
...
92 move [Base:[R188|L] Disp: 104|L] [R194|L]
94 null_check [R194|L] [bci:26]
96 convert [l2i] [R180|J] [R195|I]
98 shift_left [R180|J] [int:2|I] [R180|J]
100 move [R195|I] [Base:[R189|J] Index:[R180|J] Disp: 0|I]
102 move [Base:[R188|L] Disp: 104|L] [R196|L]
104 null_check [R196|L] [bci:33]
106 move [Base:[R189|J] Index:[R180|J] * 4 Disp: 0|I] [R197|I]
...
At instruction #96, the long index (R180) is converted to an int and is
stored into R195.
At instruction #100, the int index (R195) is stored into the memory
region allocated with unsafe. However, as we store an int, the index
used to address the destination of the store must be scaled by 4. As a
result, at instruction #98 the long index (from R180) is scaled by 4,
stored back into R180, and is then used in instruction #100.
At instruction #106, a load from the same memory location is attempted
as where we have stored before. R180 is used as scale, but the compiler
scales R180 once more by 4 (in addition to the scaling that was already
done at #98).
As a result, the UnsafeGetRaw accesses an incorrect memory address,
which result in data corruption and eventually a SIGSEGV.
HIR instruction #96 is generated by LIRGenerator::do_UnsafePutRaw (lines
2190--2193 in c1_LIRGenerator.cpp): index_op is scaled by log2_scale and
is stored back into index_op.
HIR instruction #106 is generated by LIRGenerator::do_UnsafeGetRaw (line
2106 in c1_LIRGenerator.cpp): The previously scaled index_op is reused
and an additional scaling by log2_scale is performed.
Solution:
- change the scaling code in do_UnsafePutRaw to store result into a new
temporary register tmp and not back into index_op (as index_op is
possibly reused later);
- change the scaling code in do_UnsafePutRaw to embed the scale directly
into the instruction on Intel architectures (as it is done by
do_UnsafeGetRaw);
- do_UnsafePutRaw and do_UnsafeGetRaw function similarly, so refactor
both methods to make the similarities more obvious from the source code;
- give new names to temporary registers to improve readability of the
code, for example at places like:
2053 base_op = new_register(T_INT);
2054 __ convert(Bytecodes::_l2i, base.result(), base_op); # base op
is originally base.result()
becomes
2059 LIR_Opr tmp = new_register(T_INT);
2060 __ convert(Bytecodes::_l2i, base_op, tmp);
2061 base_op = tmp;
Webrev: http://cr.openjdk.java.net/~zmajo/8076445/webrev.00/
Testing:
- add new test: CheckC1OptimizedUnsafeIntrinsics.java;
- CheckC1OptimizedUnsafeIntrinsics.java: fails on 5/9 JPRT platforms if
executed without the fix;
- JPRT: all tests pass (including CheckC1OptimizedUnsafeIntrinsics.java).
Thank you and best regards,
Zoltan
More information about the hotspot-compiler-dev
mailing list