Skip to content

Commit ccb0ca8

Browse files
committed
8368274: [lworld] Unsafe.compareAndExchangeFlatValue() wrongly assumes padding bytes are the same for identical value objects
Reviewed-by: mcimadamore
1 parent b2f45e0 commit ccb0ca8

File tree

2 files changed

+66
-44
lines changed

2 files changed

+66
-44
lines changed

src/java.base/share/classes/jdk/internal/misc/Unsafe.java

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
package jdk.internal.misc;
2727

28-
import jdk.internal.value.ValueClass;
2928
import jdk.internal.vm.annotation.AOTRuntimeSetup;
3029
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
3130
import jdk.internal.vm.annotation.ForceInline;
@@ -1711,15 +1710,8 @@ public final <V> boolean compareAndSetFlatValue(Object o, long offset,
17111710
Class<?> valueType,
17121711
V expected,
17131712
V x) {
1714-
while (true) {
1715-
Object witness = getFlatValueVolatile(o, offset, layout, valueType);
1716-
if (witness != expected) {
1717-
return false;
1718-
}
1719-
if (compareAndSetFlatValueAsBytes(o, offset, layout, valueType, witness, x)) {
1720-
return true;
1721-
}
1722-
}
1713+
Object[] array = newSpecialArray(valueType, 2, layout);
1714+
return compareAndSetFlatValueAsBytes(array, o, offset, layout, valueType, expected, x);
17231715
}
17241716

17251717
@IntrinsicCandidate
@@ -1753,15 +1745,9 @@ public final <V> Object compareAndExchangeFlatValue(Object o, long offset,
17531745
Class<?> valueType,
17541746
V expected,
17551747
V x) {
1756-
while (true) {
1757-
Object witness = getFlatValueVolatile(o, offset, layout, valueType);
1758-
if (witness != expected) {
1759-
return witness;
1760-
}
1761-
if (compareAndSetFlatValueAsBytes(o, offset, layout, valueType, witness, x)) {
1762-
return witness;
1763-
}
1764-
}
1748+
Object[] array = newSpecialArray(valueType, 2, layout);
1749+
compareAndSetFlatValueAsBytes(array, o, offset, layout, valueType, expected, x);
1750+
return array[0];
17651751
}
17661752

17671753
@IntrinsicCandidate
@@ -2877,38 +2863,75 @@ public final void putDoubleOpaque(Object o, long offset, double x) {
28772863
}
28782864

28792865
@ForceInline
2880-
private boolean compareAndSetFlatValueAsBytes(Object o, long offset, int layout, Class<?> valueType, Object expected, Object x) {
2881-
// We turn the payload of an atomic value into a numeric value (of suitable type)
2882-
// by storing the value into an array element (of matching layout) and by reading
2883-
// back the array element as an integral value. After which we can implement the CAS
2884-
// as a plain numeric CAS. Note: this only works if the payload contains no oops
2885-
// (see VarHandles::isAtomicFlat).
2886-
Object[] expectedArray = newSpecialArray(valueType, 1, layout);
2887-
Object xArray = newSpecialArray(valueType, 1, layout);
2888-
long base = arrayInstanceBaseOffset(expectedArray);
2889-
int scale = arrayInstanceIndexScale(expectedArray);
2890-
putFlatValue(expectedArray, base, layout, valueType, expected);
2891-
putFlatValue(xArray, base, layout, valueType, x);
2866+
private boolean compareAndSetFlatValueAsBytes(Object[] array, Object o, long offset, int layout, Class<?> valueType, Object expected, Object x) {
2867+
// We can convert between a value object and a binary value (of suitable size) using array elements.
2868+
// This only works if the payload contains no oops (see VarHandles::isAtomicFlat).
2869+
// Thus, we can implement the CAS with a plain numeric CAS.
2870+
2871+
// array[0]: witness (put as binary, get as object), at base
2872+
// array[1]: x (put as object, get as binary), at base + scale
2873+
// When witness == expected, the witness binary may be different from the expected binary.
2874+
// This happens when compiler does not zero unused positions in the witness.
2875+
// So we must obtain the witness binary and use it as expected binary for the numeric CAS.
2876+
long base = arrayInstanceBaseOffset(array);
2877+
int scale = arrayInstanceIndexScale(array);
2878+
putFlatValue(array, base + scale, layout, valueType, x); // put x as object
28922879
switch (scale) {
28932880
case 1: {
2894-
byte expectedByte = getByte(expectedArray, base);
2895-
byte xByte = getByte(xArray, base);
2896-
return compareAndSetByte(o, offset, expectedByte, xByte);
2881+
do {
2882+
byte witnessByte = getByteVolatile(o, offset);
2883+
putByte(array, base, witnessByte); // put witness as binary
2884+
Object witness = getFlatValue(array, base, layout, valueType); // get witness as object
2885+
if (witness != expected) {
2886+
return false;
2887+
}
2888+
byte xByte = getByte(array, base + scale); // get x as binary
2889+
if (compareAndSetByte(o, offset, witnessByte, xByte)) {
2890+
return true;
2891+
}
2892+
} while (true);
28972893
}
28982894
case 2: {
2899-
short expectedShort = getShort(expectedArray, base);
2900-
short xShort = getShort(xArray, base);
2901-
return compareAndSetShort(o, offset, expectedShort, xShort);
2895+
do {
2896+
short witnessShort = getShortVolatile(o, offset);
2897+
putShort(array, base, witnessShort); // put witness as binary
2898+
Object witness = getFlatValue(array, base, layout, valueType); // get witness as object
2899+
if (witness != expected) {
2900+
return false;
2901+
}
2902+
short xShort = getShort(array, base + scale); // get x as binary
2903+
if (compareAndSetShort(o, offset, witnessShort, xShort)) {
2904+
return true;
2905+
}
2906+
} while (true);
29022907
}
29032908
case 4: {
2904-
int expectedInt = getInt(expectedArray, base);
2905-
int xInt = getInt(xArray, base);
2906-
return compareAndSetInt(o, offset, expectedInt, xInt);
2909+
do {
2910+
int witnessInt = getIntVolatile(o, offset);
2911+
putInt(array, base, witnessInt); // put witness as binary
2912+
Object witness = getFlatValue(array, base, layout, valueType); // get witness as object
2913+
if (witness != expected) {
2914+
return false;
2915+
}
2916+
int xInt = getInt(array, base + scale); // get x as binary
2917+
if (compareAndSetInt(o, offset, witnessInt, xInt)) {
2918+
return true;
2919+
}
2920+
} while (true);
29072921
}
29082922
case 8: {
2909-
long expectedLong = getLong(expectedArray, base);
2910-
long xLong = getLong(xArray, base);
2911-
return compareAndSetLong(o, offset, expectedLong, xLong);
2923+
do {
2924+
long witnessLong = getLongVolatile(o, offset);
2925+
putLong(array, base, witnessLong); // put witness as binary
2926+
Object witness = getFlatValue(array, base, layout, valueType);
2927+
if (witness != expected) {
2928+
return false;
2929+
}
2930+
long xLong = getLong(array, base + scale); // get x as binary
2931+
if (compareAndSetLong(o, offset, witnessLong, xLong)) {
2932+
return true;
2933+
}
2934+
} while (true);
29122935
}
29132936
default: {
29142937
throw new UnsupportedOperationException();

test/jdk/ProblemList.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,6 @@ tools/sincechecker/modules/jdk.management.jfr/JdkManagementJfrCheckSince.java 83
796796

797797
# valhalla
798798
build/CheckFiles.java 8376088 generic-all
799-
java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessValue.java 8367346 generic-all
800799

801800
jdk/classfile/AccessFlagsTest.java 8366270 generic-all
802801
jdk/jfr/event/runtime/TestClassLoaderStatsEvent.java 8366820 generic-all

0 commit comments

Comments
 (0)