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  * @modules java.base/jdk.internal.org.objectweb.asm
  29  *          java.base/jdk.internal.misc
  30  *          java.management
  31  * @compile -XDignore.symbol.file BadMethodHandles.java
  32  * @run main/othervm BadMethodHandles
  33  */
  34 
  35 import jdk.internal.org.objectweb.asm.*;
  36 import java.io.FileOutputStream;
  37 import java.lang.reflect.InvocationTargetException;
  38 import java.lang.invoke.MethodHandle;
  39 import java.lang.invoke.MethodHandles;
  40 import java.lang.invoke.MethodType;
  41 import static jdk.internal.org.objectweb.asm.Opcodes.*;
  42 
  43 public class BadMethodHandles {
  44 
  45     static byte[] dumpBadInterfaceMethodref() {
  46         ClassWriter cw = new ClassWriter(0);
  47         cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadInterfaceMethodref", null, "java/lang/Object", null);
  48         Handle handle1 =
  49             new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "m", "()V");
  50         Handle handle2 =
  51             new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "staticM", "()V");
  52 
  53         {
  54             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
  55             mv.visitCode();
  56             mv.visitVarInsn(ALOAD, 0);
  57             mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
  58             mv.visitInsn(RETURN);
  59             mv.visitMaxs(1, 1);
  60             mv.visitEnd();
  61         }
  62         {
  63             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null);
  64             mv.visitCode();
  65             mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
  66             mv.visitLdcInsn("hello from m");
  67             mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
  68             mv.visitInsn(RETURN);
  69             mv.visitMaxs(3, 1);
  70             mv.visitEnd();
  71         }
  72         {
  73             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null);
  74             mv.visitCode();
  75             mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
  76             mv.visitLdcInsn("hello from staticM");
  77             mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
  78             mv.visitInsn(RETURN);
  79             mv.visitMaxs(3, 1);
  80             mv.visitEnd();
  81         }
  82 
  83         {
  84             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null);
  85             mv.visitCode();
  86             // REF_invokeStatic
  87             mv.visitLdcInsn(handle1);
  88             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
  89             mv.visitInsn(RETURN);
  90             mv.visitMaxs(1, 1);
  91             mv.visitEnd();
  92         }
  93 
  94         {
  95             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null);
  96             mv.visitCode();
  97             // REF_invokeStatic
  98             mv.visitLdcInsn(handle2);
  99             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
 100             mv.visitInsn(RETURN);
 101             mv.visitMaxs(1, 1);
 102             mv.visitEnd();
 103         }
 104 
 105         cw.visitEnd();
 106         return cw.toByteArray();
 107     }
 108 
 109     static byte[] dumpIBad() {
 110         ClassWriter cw = new ClassWriter(0);
 111         cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "IBad", null, "java/lang/Object", null);
 112         {
 113             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null);
 114             mv.visitCode();
 115             mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
 116             mv.visitLdcInsn("hello from m");
 117             mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
 118             mv.visitInsn(RETURN);
 119             mv.visitMaxs(3, 1);
 120             mv.visitEnd();
 121         }
 122         {
 123             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null);
 124             mv.visitCode();
 125             mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
 126             mv.visitLdcInsn("hello from staticM");
 127             mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
 128             mv.visitInsn(RETURN);
 129             mv.visitMaxs(3, 1);
 130             mv.visitEnd();
 131         }
 132         cw.visitEnd();
 133         return cw.toByteArray();
 134     }
 135 
 136     static byte[] dumpBadMethodref() {
 137         ClassWriter cw = new ClassWriter(0);
 138         cw.visit(52, ACC_PUBLIC | ACC_SUPER,  "BadMethodref", null, "java/lang/Object", new String[]{"IBad"});
 139         Handle handle1 =
 140             new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "m", "()V");
 141         Handle handle2 =
 142             new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "staticM", "()V");
 143 
 144         {
 145             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
 146             mv.visitCode();
 147             mv.visitVarInsn(ALOAD, 0);
 148             mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
 149             mv.visitInsn(RETURN);
 150             mv.visitMaxs(1, 1);
 151             mv.visitEnd();
 152         }
 153 
 154         {
 155             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null);
 156             mv.visitCode();
 157             // REF_invokeStatic
 158             mv.visitLdcInsn(handle1);
 159             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
 160             mv.visitInsn(RETURN);
 161             mv.visitMaxs(1, 1);
 162             mv.visitEnd();
 163         }
 164 
 165         {
 166             MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null);
 167             mv.visitCode();
 168             // REF_invokeStatic
 169             mv.visitLdcInsn(handle2);
 170             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
 171             mv.visitInsn(RETURN);
 172             mv.visitMaxs(1, 1);
 173             mv.visitEnd();
 174         }
 175 
 176         cw.visitEnd();
 177         return cw.toByteArray();
 178     }
 179     static class CL extends ClassLoader {
 180         @Override
 181         protected Class<?> findClass(String name) throws ClassNotFoundException {
 182             byte[] classBytes = null;
 183             switch (name) {
 184             case "BadInterfaceMethodref": classBytes = dumpBadInterfaceMethodref(); break;
 185             case "BadMethodref"         : classBytes = dumpBadMethodref(); break;
 186             case "IBad"                 : classBytes = dumpIBad(); break;
 187             default                     : throw new ClassNotFoundException(name);
 188             }
 189             return defineClass(name, classBytes, 0, classBytes.length);
 190         }
 191     }
 192 
 193     public static void main(String[] args) throws Throwable {
 194         try (FileOutputStream fos = new FileOutputStream("BadInterfaceMethodref.class")) {
 195           fos.write(dumpBadInterfaceMethodref());
 196         }
 197         try (FileOutputStream fos = new FileOutputStream("IBad.class")) {
 198           fos.write(dumpIBad());
 199         }
 200         try (FileOutputStream fos = new FileOutputStream("BadMethodref.class")) {
 201           fos.write(dumpBadMethodref());
 202         }
 203 
 204         Class<?> cls = (new CL()).loadClass("BadInterfaceMethodref");
 205         String[] methods = {"runm", "runStaticM"};
 206         System.out.println("Test BadInterfaceMethodref:");
 207         int success = 0;
 208         for (String name : methods) {
 209             try {
 210                 System.out.printf("invoke %s: \n", name);
 211                 cls.getMethod(name).invoke(cls.newInstance());
 212                 System.out.println("FAILED - ICCE should be thrown");
 213             } catch (Throwable e) {
 214                 if (e instanceof InvocationTargetException && e.getCause() != null &&
 215                     e.getCause() instanceof IncompatibleClassChangeError) {
 216                     System.out.println("PASSED - expected ICCE thrown");
 217                     success++;
 218                     continue;
 219                 } else {
 220                     System.out.println("FAILED with wrong exception" + e);
 221                     throw e;
 222                 }
 223             }
 224         }
 225         if (success != methods.length) {
 226            throw new Exception("BadInterfaceMethodRef Failed to catch IncompatibleClassChangeError");
 227         }
 228         System.out.println("Test BadMethodref:");
 229         cls = (new CL()).loadClass("BadMethodref");
 230         success = 0;
 231         for (String name : methods) {
 232             try {
 233                 System.out.printf("invoke %s: \n", name);
 234                 cls.getMethod(name).invoke(cls.newInstance());
 235                 System.out.println("FAILED - ICCE should be thrown");
 236             } catch (Throwable e) {
 237                 if (e instanceof InvocationTargetException && e.getCause() != null &&
 238                     e.getCause() instanceof IncompatibleClassChangeError) {
 239                     System.out.println("PASSED - expected ICCE thrown");
 240                     success++;
 241                     continue;
 242                 } else {
 243                     System.out.println("FAILED with wrong exception" + e);
 244                     throw e;
 245                 }
 246             }
 247          }
 248          if (success != methods.length) {
 249             throw new Exception("BadMethodRef Failed to catch IncompatibleClassChangeError");
 250          }
 251 
 252     }
 253 }