1 /*
   2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 8087223
  27  * @summary Adding constantTag to keep method call consistent with it.
  28  * @library /testlibrary
  29  * @modules java.base/jdk.internal.org.objectweb.asm
  30  *          java.base/jdk.internal.misc
  31  *          java.management
  32  * @compile -XDignore.symbol.file BadMethodHandles.java
  33  * @run main/othervm BadMethodHandles
  34  */
  35 
  36 import jdk.internal.org.objectweb.asm.*;
  37 import java.io.FileOutputStream;
  38 import java.lang.reflect.InvocationTargetException;
  39 import java.lang.invoke.MethodHandle;
  40 import java.lang.invoke.MethodHandles;
  41 import java.lang.invoke.MethodType;
  42 import static jdk.internal.org.objectweb.asm.Opcodes.*;
  43 
  44 public class BadMethodHandles {
  45 
  46     static byte[] dumpBadInterfaceMethodref() {
  47         ClassWriter cw = new ClassWriter(0);
  48         cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadInterfaceMethodref", null, "java/lang/Object", null);
  49         Handle handle1 =
  50             new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "m", "()V");
  51         Handle handle2 =
  52             new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "staticM", "()V");
  53 
  54         {
  55             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
  56             mv.visitCode();
  57             mv.visitVarInsn(ALOAD, 0);
  58             mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
  59             mv.visitInsn(RETURN);
  60             mv.visitMaxs(1, 1);
  61             mv.visitEnd();
  62         }
  63         {
  64             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null);
  65             mv.visitCode();
  66             mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
  67             mv.visitLdcInsn("hello from m");
  68             mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
  69             mv.visitInsn(RETURN);
  70             mv.visitMaxs(3, 1);
  71             mv.visitEnd();
  72         }
  73         {
  74             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null);
  75             mv.visitCode();
  76             mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
  77             mv.visitLdcInsn("hello from staticM");
  78             mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
  79             mv.visitInsn(RETURN);
  80             mv.visitMaxs(3, 1);
  81             mv.visitEnd();
  82         }
  83 
  84         {
  85             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null);
  86             mv.visitCode();
  87             // REF_invokeStatic
  88             mv.visitLdcInsn(handle1);
  89             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
  90             mv.visitInsn(RETURN);
  91             mv.visitMaxs(1, 1);
  92             mv.visitEnd();
  93         }
  94 
  95         {
  96             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null);
  97             mv.visitCode();
  98             // REF_invokeStatic
  99             mv.visitLdcInsn(handle2);
 100             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
 101             mv.visitInsn(RETURN);
 102             mv.visitMaxs(1, 1);
 103             mv.visitEnd();
 104         }
 105 
 106         cw.visitEnd();
 107         return cw.toByteArray();
 108     }
 109 
 110     static byte[] dumpIBad() {
 111         ClassWriter cw = new ClassWriter(0);
 112         cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "IBad", null, "java/lang/Object", null);
 113         {
 114             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null);
 115             mv.visitCode();
 116             mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
 117             mv.visitLdcInsn("hello from m");
 118             mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
 119             mv.visitInsn(RETURN);
 120             mv.visitMaxs(3, 1);
 121             mv.visitEnd();
 122         }
 123         {
 124             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null);
 125             mv.visitCode();
 126             mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
 127             mv.visitLdcInsn("hello from staticM");
 128             mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
 129             mv.visitInsn(RETURN);
 130             mv.visitMaxs(3, 1);
 131             mv.visitEnd();
 132         }
 133         cw.visitEnd();
 134         return cw.toByteArray();
 135     }
 136 
 137     static byte[] dumpBadMethodref() {
 138         ClassWriter cw = new ClassWriter(0);
 139         cw.visit(52, ACC_PUBLIC | ACC_SUPER,  "BadMethodref", null, "java/lang/Object", new String[]{"IBad"});
 140         Handle handle1 =
 141             new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "m", "()V");
 142         Handle handle2 =
 143             new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "staticM", "()V");
 144 
 145         {
 146             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
 147             mv.visitCode();
 148             mv.visitVarInsn(ALOAD, 0);
 149             mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
 150             mv.visitInsn(RETURN);
 151             mv.visitMaxs(1, 1);
 152             mv.visitEnd();
 153         }
 154 
 155         {
 156             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null);
 157             mv.visitCode();
 158             // REF_invokeStatic
 159             mv.visitLdcInsn(handle1);
 160             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
 161             mv.visitInsn(RETURN);
 162             mv.visitMaxs(1, 1);
 163             mv.visitEnd();
 164         }
 165 
 166         {
 167             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null);
 168             mv.visitCode();
 169             // REF_invokeStatic
 170             mv.visitLdcInsn(handle2);
 171             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
 172             mv.visitInsn(RETURN);
 173             mv.visitMaxs(1, 1);
 174             mv.visitEnd();
 175         }
 176 
 177         cw.visitEnd();
 178         return cw.toByteArray();
 179     }
 180     static class CL extends ClassLoader {
 181         @Override
 182         protected Class<?> findClass(String name) throws ClassNotFoundException {
 183             byte[] classBytes = null;
 184             switch (name) {
 185             case "BadInterfaceMethodref": classBytes = dumpBadInterfaceMethodref(); break;
 186             case "BadMethodref"         : classBytes = dumpBadMethodref(); break;
 187             case "IBad"                 : classBytes = dumpIBad(); break;
 188             default                     : throw new ClassNotFoundException(name);
 189             }
 190             return defineClass(name, classBytes, 0, classBytes.length);
 191         }
 192     }
 193 
 194     public static void main(String[] args) throws Throwable {
 195         try (FileOutputStream fos = new FileOutputStream("BadInterfaceMethodref.class")) {
 196           fos.write(dumpBadInterfaceMethodref());
 197         }
 198         try (FileOutputStream fos = new FileOutputStream("IBad.class")) {
 199           fos.write(dumpIBad());
 200         }
 201         try (FileOutputStream fos = new FileOutputStream("BadMethodref.class")) {
 202           fos.write(dumpBadMethodref());
 203         }
 204 
 205         Class<?> cls = (new CL()).loadClass("BadInterfaceMethodref");
 206         String[] methods = {"runm", "runStaticM"};
 207         System.out.println("Test BadInterfaceMethodref:");
 208         int success = 0;
 209         for (String name : methods) {
 210             try {
 211                 System.out.printf("invoke %s: \n", name);
 212                 cls.getMethod(name).invoke(cls.newInstance());
 213                 System.out.println("FAILED - ICCE should be thrown");
 214             } catch (Throwable e) {
 215                 if (e instanceof InvocationTargetException && e.getCause() != null &&
 216                     e.getCause() instanceof IncompatibleClassChangeError) {
 217                     System.out.println("PASSED - expected ICCE thrown");
 218                     success++;
 219                     continue;
 220                 } else {
 221                     System.out.println("FAILED with wrong exception" + e);
 222                     throw e;
 223                 }
 224             }
 225         }
 226         if (success != methods.length) {
 227            throw new Exception("BadInterfaceMethodRef Failed to catch IncompatibleClassChangeError");
 228         }
 229         System.out.println("Test BadMethodref:");
 230         cls = (new CL()).loadClass("BadMethodref");
 231         success = 0;
 232         for (String name : methods) {
 233             try {
 234                 System.out.printf("invoke %s: \n", name);
 235                 cls.getMethod(name).invoke(cls.newInstance());
 236                 System.out.println("FAILED - ICCE should be thrown");
 237             } catch (Throwable e) {
 238                 if (e instanceof InvocationTargetException && e.getCause() != null &&
 239                     e.getCause() instanceof IncompatibleClassChangeError) {
 240                     System.out.println("PASSED - expected ICCE thrown");
 241                     success++;
 242                     continue;
 243                 } else {
 244                     System.out.println("FAILED with wrong exception" + e);
 245                     throw e;
 246                 }
 247             }
 248          }
 249          if (success != methods.length) {
 250             throw new Exception("BadMethodRef Failed to catch IncompatibleClassChangeError");
 251          }
 252 
 253     }
 254 }