1 /* 2 * Copyright (c) 2014, 2015, 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 import java.io.File; 25 import java.io.FileOutputStream; 26 27 import jdk.internal.org.objectweb.asm.ClassWriter; 28 import jdk.internal.org.objectweb.asm.MethodVisitor; 29 import static jdk.internal.org.objectweb.asm.Opcodes.*; 30 31 import jdk.test.lib.*; 32 33 /* 34 * @test 35 * @summary Test that anewarray bytecode is valid only if it specifies 255 or fewer dimensions. 36 * @library /testlibrary 37 * @modules java.base/jdk.internal.org.objectweb.asm 38 * java.base/jdk.internal.misc 39 * java.management 40 * @compile -XDignore.symbol.file TestANewArray.java 41 * @run main/othervm TestANewArray 49 42 * @run main/othervm TestANewArray 50 43 * @run main/othervm TestANewArray 51 44 * @run main/othervm TestANewArray 52 45 */ 46 47 /* 48 * Testing anewarray instruction with 254, 255 & 264 dimensions to verify JVMS 8, 49 * Section 4.9.1, Static Constraints that states the following: 50 * 51 * "No anewarray instruction may be used to create an array of more than 255 dimensions." 52 * 53 */ 54 55 public class TestANewArray { 56 57 static String classCName = null; // the generated class name 58 59 static final int test_Dimension_254 = 254; // should always pass 60 static final int test_Dimension_255 = 255; // should always pass, except for cfv 49 61 static final int test_Dimension_264 = 264; // should always fail 62 63 static final String array_Dimension_254 = genArrayDim(test_Dimension_254); 64 static final String array_Dimension_255 = genArrayDim(test_Dimension_255); 65 static final String array_Dimension_264 = genArrayDim(test_Dimension_264); 66 67 public static void main(String... args) throws Exception { 68 int cfv = Integer.parseInt(args[0]); 69 70 // 254 array dimensions 71 byte[] classFile_254 = dumpClassFile(cfv, test_Dimension_254, array_Dimension_254); 72 writeClassFileFromByteArray(classFile_254); 73 System.err.println("Running with cfv: " + cfv + ", test_Dimension_254"); 74 ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, "-verify", "-cp", ".", classCName); 75 OutputAnalyzer output = new OutputAnalyzer(pb.start()); 76 output.shouldNotContain("java.lang.VerifyError"); 77 output.shouldHaveExitValue(0); 78 79 // 255 array dimensions 80 byte[] classFile_255 = dumpClassFile(cfv, test_Dimension_255, array_Dimension_255); 81 writeClassFileFromByteArray(classFile_255); 82 System.err.println("Running with cfv: " + cfv + ", test_Dimension_255"); 83 pb = ProcessTools.createJavaProcessBuilder(true, "-verify", "-cp", ".", classCName); 84 output = new OutputAnalyzer(pb.start()); 85 if (cfv == 49) { 86 // The type-inferencing verifier used for <=49.0 ClassFiles detects an anewarray instruction 87 // with exactly 255 dimensions and incorrectly issues the "Array with too many dimensions" VerifyError. 88 output.shouldContain("Array with too many dimensions"); 89 output.shouldHaveExitValue(1); 90 } else { 91 // 255 dimensions should always pass, except for cfv 49 92 output.shouldNotContain("java.lang.VerifyError"); 93 output.shouldNotContain("java.lang.ClassFormatError"); 94 output.shouldHaveExitValue(0); 95 } 96 97 // 264 array dimensions 98 byte[] classFile_264 = dumpClassFile(cfv, test_Dimension_264, array_Dimension_264); 99 writeClassFileFromByteArray(classFile_264); 100 System.err.println("Running with cfv: " + cfv + ", test_Dimension_264"); 101 pb = ProcessTools.createJavaProcessBuilder(true, "-verify", "-cp", ".", classCName); 102 output = new OutputAnalyzer(pb.start()); 103 output.shouldContain("java.lang.ClassFormatError"); 104 output.shouldHaveExitValue(1); 105 } 106 107 public static byte[] dumpClassFile(int cfv, int testDimension264, String arrayDim) throws Exception { 108 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 109 MethodVisitor mv; 110 111 classCName = "classCName_" + cfv + "_" + testDimension264; 112 113 cw.visit(cfv, ACC_PUBLIC + ACC_SUPER, classCName, null, "java/lang/Object", null); 114 { 115 mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 116 mv.visitCode(); 117 mv.visitVarInsn(ALOAD, 0); 118 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 119 mv.visitInsn(RETURN); 120 mv.visitMaxs(1, 1); 121 mv.visitEnd(); 122 } 123 { // classCName main method 124 mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); 125 mv.visitCode(); 126 mv.visitIntInsn(BIPUSH, 1); 127 mv.visitTypeInsn(ANEWARRAY, arrayDim); // Test ANEWARRAY bytecode with various dimensions 128 mv.visitInsn(RETURN); 129 mv.visitMaxs(2, 2); 130 mv.visitEnd(); 131 } 132 cw.visitEnd(); 133 return cw.toByteArray(); 134 } 135 136 public static FileOutputStream writeClassFileFromByteArray(byte[] classFileByteArray) throws Exception { 137 FileOutputStream fos = new FileOutputStream(new File(classCName + ".class")); 138 fos.write(classFileByteArray); 139 fos.close(); 140 return fos; 141 } 142 143 private static String genArrayDim(int testDim) { 144 StringBuilder array_Dimension = new StringBuilder(); 145 for (int i = 0; i < testDim; i++) 146 { 147 array_Dimension.append("["); 148 } 149 return array_Dimension.append("Ljava/lang/Object;").toString(); 150 } 151 }