8138840: NPE when compiling bitwise operations with illegal operand types
authormcimadamore
Mon, 12 Oct 2015 12:24:33 +0100
changeset 33018 9790ed482dd0
parent 32954 7db0663a5e96
child 33019 2dc64d1f5e18
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 Summary: Certain binary operator checks are accepting more operands than required. Reviewed-by: jlahoda
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java
langtools/test/tools/javac/8138840/T8138840.java
langtools/test/tools/javac/8138840/T8138840.out
langtools/test/tools/javac/8138840/T8139243.java
langtools/test/tools/javac/8138840/T8139243.out
langtools/test/tools/javac/8138840/T8139249.java
langtools/test/tools/javac/8138840/T8139249.out
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Wed Jul 05 20:53:25 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Mon Oct 12 12:24:33 2015 +0100
@@ -142,6 +142,10 @@
         return false;
     }
 
+    public boolean isIntegral() {
+        return false;
+    }
+
     public boolean isPrimitive() {
         return false;
     }
@@ -697,6 +701,20 @@
         }
 
         @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;
         }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java	Wed Jul 05 20:53:25 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java	Mon Oct 12 12:24:33 2015 +0100
@@ -404,13 +404,20 @@
      */
     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 @@
      */
     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 @@
 
         @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 @@
 
         @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 @@
                         .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 @@
                     .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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8138840/T8138840.java	Mon Oct 12 12:24:33 2015 +0100
@@ -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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8138840/T8138840.out	Mon Oct 12 12:24:33 2015 +0100
@@ -0,0 +1,2 @@
+T8138840.java:10:22: compiler.err.operator.cant.be.applied.1: &, int, double
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8138840/T8139243.java	Mon Oct 12 12:24:33 2015 +0100
@@ -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() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8138840/T8139243.out	Mon Oct 12 12:24:33 2015 +0100
@@ -0,0 +1,2 @@
+T8139243.java:12:11: compiler.err.operator.cant.be.applied.1: +, java.lang.String, void
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8138840/T8139249.java	Mon Oct 12 12:24:33 2015 +0100
@@ -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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8138840/T8139249.out	Mon Oct 12 12:24:33 2015 +0100
@@ -0,0 +1,2 @@
+T8139249.java:11:20: compiler.err.operator.cant.be.applied: ~, float
+1 error