8354323: Safeguard SwitchBootstraps.typeSwitch when used outside the compiler

Reviewed-by: jlahoda, liach
This commit is contained in:
Aggelos Biboudis 2025-05-22 08:36:47 +00:00
parent 85b24c3c4e
commit c0665efd4f
3 changed files with 39 additions and 16 deletions

View File

@ -546,7 +546,11 @@ public final class SwitchBootstraps {
Object caseLabel = caseLabels[idx];
cb.labelBinding(caseTargets[idx]);
if (caseLabel instanceof Class<?> classLabel) {
if (unconditionalExactnessCheck(selectorType, classLabel)) {
if (isNotValidPair(selectorType, caseLabel)){
cb.goto_(next);
continue;
}
else if (unconditionalExactnessCheck(selectorType, classLabel)) {
//nothing - unconditionally use this case
} else if (classLabel.isPrimitive()) {
if (!selectorType.isPrimitive() && !Wrapper.isWrapperNumericOrBooleanType(selectorType)) {
@ -717,6 +721,11 @@ public final class SwitchBootstraps {
};
}
private static boolean isNotValidPair(Class<?> selectorType, Object caseLabel) {
return (selectorType == boolean.class && caseLabel != boolean.class && caseLabel != Boolean.class) ||
(selectorType != boolean.class && selectorType.isPrimitive() && (caseLabel == boolean.class || caseLabel == Boolean.class));
}
/*
* Construct the method handle that represents the method int typeSwitch(Object, int, BiPredicate, List)
*/
@ -769,11 +778,11 @@ public final class SwitchBootstraps {
return true;
}
else if (selectorType.equals(targetType) ||
((selectorType.equals(byte.class) && !targetType.equals(char.class)) ||
(selectorType.equals(short.class) && (selectorWrapper.isStrictSubRangeOf(targetWrapper))) ||
(selectorType.equals(char.class) && (selectorWrapper.isStrictSubRangeOf(targetWrapper))) ||
(selectorType.equals(int.class) && (targetType.equals(double.class) || targetType.equals(long.class))) ||
(selectorType.equals(float.class) && (selectorWrapper.isStrictSubRangeOf(targetWrapper))))) return true;
(targetType.isPrimitive() && selectorType.isPrimitive() &&
(selectorWrapper.isStrictSubRangeOf(targetWrapper) &&
!((selectorType.equals(byte.class) && targetType.equals(char.class)) ||
(selectorType.equals(int.class) && targetType.equals(float.class)) ||
(selectorType.equals(long.class) && (targetType.equals(double.class) || targetType.equals(float.class))))))) return true;
return false;
}

View File

@ -5085,16 +5085,12 @@ public class Types {
* @param targetType Target type
*/
public boolean isUnconditionallyExactPrimitives(Type selectorType, Type targetType) {
if (isSameType(selectorType, targetType)) {
return true;
}
return (selectorType.isPrimitive() && targetType.isPrimitive()) &&
((selectorType.hasTag(BYTE) && !targetType.hasTag(CHAR)) ||
(selectorType.hasTag(SHORT) && (selectorType.getTag().isStrictSubRangeOf(targetType.getTag()))) ||
(selectorType.hasTag(CHAR) && (selectorType.getTag().isStrictSubRangeOf(targetType.getTag()))) ||
(selectorType.hasTag(INT) && (targetType.hasTag(DOUBLE) || targetType.hasTag(LONG))) ||
(selectorType.hasTag(FLOAT) && (selectorType.getTag().isStrictSubRangeOf(targetType.getTag()))));
return isSameType(selectorType, targetType) ||
(selectorType.isPrimitive() && targetType.isPrimitive()) &&
((selectorType.getTag().isStrictSubRangeOf(targetType.getTag())) &&
!((selectorType.hasTag(BYTE) && targetType.hasTag(CHAR)) ||
(selectorType.hasTag(INT) && targetType.hasTag(FLOAT)) ||
(selectorType.hasTag(LONG) && (targetType.hasTag(DOUBLE) || targetType.hasTag(FLOAT)))));
}
// </editor-fold>

View File

@ -74,6 +74,12 @@ public class SwitchBootstrapsTest {
assertEquals(-1, (int) indy.invoke(null, start));
}
private void testPrimitiveType(Object target, Class<?> targetType, int start, int result, Object... labels) throws Throwable {
MethodType switchType = MethodType.methodType(int.class, targetType, int.class);
MethodHandle indy = ((CallSite) BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", switchType, labels)).dynamicInvoker();
assertEquals((int) indy.invoke(target, start), result);
}
private void testEnum(Enum<?> target, int start, int result, Object... labels) throws Throwable {
testEnum(target.getClass(), target, start, result, labels);
}
@ -132,6 +138,18 @@ public class SwitchBootstrapsTest {
}, 0, 1, 1L);
}
public void testPrimitiveTypes() throws Throwable {
testPrimitiveType((short) 1, short.class, 0, 1, String.class);
testPrimitiveType((byte) 1, byte.class,0, 1, String.class, byte.class);
testPrimitiveType(true, boolean.class,0, 1, false, boolean.class);
testPrimitiveType(1, int.class,0, 1, String.class);
testPrimitiveType(1, int.class,0, 1, true);
testPrimitiveType(true, boolean.class,0, 1, false);
testPrimitiveType((byte) 1, byte.class,0, 1, boolean.class, byte.class);
testPrimitiveType((byte) 1, byte.class,0, 1, Boolean.class, byte.class);
testPrimitiveType(true, boolean.class,0, 1, String.class, boolean.class);
}
public void testEnums() throws Throwable {
testEnum(E1.A, 0, 2, "B", "C", "A", E1.class);
testEnum(E1.B, 0, 0, "B", "C", "A", E1.class);