8138840: NPE when compiling bitwise operations with illegal operand types

8139243: compiler crashes with exception on sum operation of String var and void method call result
8139249: Compiler crashes on unary bitwise complement with non-integral operand

Certain binary operator checks are accepting more operands than required.

Reviewed-by: jlahoda
This commit is contained in:
Maurizio Cimadamore 2015-10-12 12:24:33 +01:00
parent 119988f54a
commit 4d32c48daf
8 changed files with 91 additions and 9 deletions

View File

@ -142,6 +142,10 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
return false;
}
public boolean isIntegral() {
return false;
}
public boolean isPrimitive() {
return false;
}
@ -696,6 +700,20 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
return tag != BOOLEAN;
}
@Override
public boolean isIntegral() {
switch (tag) {
case CHAR:
case BYTE:
case SHORT:
case INT:
case LONG:
return true;
default:
return false;
}
}
@Override
public boolean isPrimitive() {
return true;

View File

@ -404,13 +404,20 @@ public class Operators {
*/
class UnaryNumericOperator extends UnaryOperatorHelper {
Predicate<Type> numericTest;
UnaryNumericOperator(Tag tag) {
this(tag, Type::isNumeric);
}
UnaryNumericOperator(Tag tag, Predicate<Type> numericTest) {
super(tag);
this.numericTest = numericTest;
}
@Override
public boolean test(Type type) {
return unaryPromotion(type).isNumeric();
return numericTest.test(unaryPromotion(type));
}
@Override
@ -462,8 +469,15 @@ public class Operators {
*/
class BinaryNumericOperator extends BinaryOperatorHelper {
Predicate<Type> numericTest;
BinaryNumericOperator(Tag tag) {
this(tag, Type::isNumeric);
}
BinaryNumericOperator(Tag tag, Predicate<Type> numericTest) {
super(tag);
this.numericTest = numericTest;
}
@Override
@ -474,7 +488,8 @@ public class Operators {
@Override
public boolean test(Type arg1, Type arg2) {
return unaryPromotion(arg1).isNumeric() && unaryPromotion(arg2).isNumeric();
return numericTest.test(unaryPromotion(arg1)) &&
numericTest.test(unaryPromotion(arg2));
}
}
@ -518,20 +533,22 @@ public class Operators {
@Override
public boolean test(Type arg1, Type arg2) {
return types.isSameType(arg1, syms.stringType) ||
boolean hasStringOp = types.isSameType(arg1, syms.stringType) ||
types.isSameType(arg2, syms.stringType);
boolean hasVoidOp = arg1.hasTag(TypeTag.VOID) || arg2.hasTag(TypeTag.VOID);
return hasStringOp && !hasVoidOp;
}
/**
* This routine applies following mappings:
* - if input type is primitive, apply numeric promotion
* - if input type is either 'null' or 'String' leave it untouched
* - if input type is either 'void', 'null' or 'String' leave it untouched
* - otherwise return 'Object'
*/
private Type stringPromotion(Type t) {
if (t.isPrimitive()) {
return unaryPromotion(t);
} else if (t.hasTag(TypeTag.BOT) ||
} else if (t.hasTag(TypeTag.VOID) || t.hasTag(TypeTag.BOT) ||
types.isSameType(t, syms.stringType)) {
return t;
} else if (t.hasTag(TypeTag.TYPEVAR)) {
@ -640,7 +657,7 @@ public class Operators {
.addUnaryOperator(FLOAT, FLOAT, fneg)
.addUnaryOperator(LONG, LONG, lneg)
.addUnaryOperator(INT, INT, ineg),
new UnaryNumericOperator(Tag.COMPL)
new UnaryNumericOperator(Tag.COMPL, Type::isIntegral)
.addUnaryOperator(LONG, LONG, lxor)
.addUnaryOperator(INT, INT, ixor),
new UnaryPrefixPostfixOperator(Tag.POSTINC)
@ -713,17 +730,17 @@ public class Operators {
.addBinaryOperator(INT, INT, INT, imod),
new BinaryBooleanOperator(Tag.BITAND)
.addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, iand),
new BinaryNumericOperator(Tag.BITAND)
new BinaryNumericOperator(Tag.BITAND, Type::isIntegral)
.addBinaryOperator(LONG, LONG, LONG, land)
.addBinaryOperator(INT, INT, INT, iand),
new BinaryBooleanOperator(Tag.BITOR)
.addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, ior),
new BinaryNumericOperator(Tag.BITOR)
new BinaryNumericOperator(Tag.BITOR, Type::isIntegral)
.addBinaryOperator(LONG, LONG, LONG, lor)
.addBinaryOperator(INT, INT, INT, ior),
new BinaryBooleanOperator(Tag.BITXOR)
.addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, ixor),
new BinaryNumericOperator(Tag.BITXOR)
new BinaryNumericOperator(Tag.BITXOR, Type::isIntegral)
.addBinaryOperator(LONG, LONG, LONG, lxor)
.addBinaryOperator(INT, INT, INT, ixor),
new BinaryShiftOperator(Tag.SL)

View File

@ -0,0 +1,12 @@
/*
* @test /nodynamiccopyright/
* @bug 8138840 8139243 8139249
* @summary Compiler crashes when compiling bitwise operations with illegal operand types
* @compile/fail/ref=T8138840.out -XDrawDiagnostics T8138840.java
*/
class T8138840 {
void test(int x, double d) {
Object o = x & d;
}
}

View File

@ -0,0 +1,2 @@
T8138840.java:10:22: compiler.err.operator.cant.be.applied.1: &, int, double
1 error

View File

@ -0,0 +1,16 @@
/*
* @test /nodynamiccopyright/
* @bug 8138840 8139243 8139249
* @summary Compiler crashes when compiling bitwise operations with illegal operand types
* 'void' is erroneously accepted as a possible operand for string concatenation
* @compile/fail/ref=T8139243.out -XDrawDiagnostics T8139243.java
*/
class T8139243 {
void test(String s) {
s += m(); // compile time error
}
void m() { }
}

View File

@ -0,0 +1,2 @@
T8139243.java:12:11: compiler.err.operator.cant.be.applied.1: +, java.lang.String, void
1 error

View File

@ -0,0 +1,13 @@
/*
* @test /nodynamiccopyright/
* @bug 8138840 8139243 8139249
* @summary Compiler crashes when compiling bitwise operations with illegal operand types
* Unary operator erroneously applied to non-integral type operand
* @compile/fail/ref=T8139249.out -XDrawDiagnostics T8139249.java
*/
class T8139249 {
void test(float f2) {
float f1 = ~f2;
}
}

View File

@ -0,0 +1,2 @@
T8139249.java:11:20: compiler.err.operator.cant.be.applied: ~, float
1 error