1 /* 2 * Copyright (c) 2014, 2017, 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 import java.io.File; 26 import java.io.FileOutputStream; 27 import jdk.test.lib.process.OutputAnalyzer; 28 import java.nio.file.Files; 29 30 import java.util.*; 31 import jdk.internal.org.objectweb.asm.*; 32 33 /** 34 * The testsets contained in this class are executed by ./VerifierTest_*.java, so that 35 * individual testsets can be executed in parallel to shorten the total time required. 36 */ 37 public class VerifierTest implements Opcodes { 38 // Test verification settings for dumping & runtime 39 static final String VFY_ALL = "-Xverify:all"; 40 static final String VFY_REMOTE = "-Xverify:remote"; // default 41 static final String VFY_NONE = "-Xverify:none"; 42 43 static final String ERR = 44 "ERROR: class VerifierTestC was loaded unexpectedly"; 45 static final String MAP_FAIL = 46 "shared archive file was created with less restrictive verification setting"; 47 static final String VFY_ERR = "java.lang.VerifyError"; 48 49 enum Testset1Part { 50 A, B 51 } 52 53 public static void main(String[] args) throws Exception { 54 String subCaseId = args[0]; 55 String jarName_verifier_test_tmp = "verifier_test_tmp" + "_" + subCaseId; 56 String jarName_verifier_test = "verifier_test" + "_" + subCaseId; 57 String jarName_greet = "greet" + "_" + subCaseId; 58 String jarName_hi = "hi" + "_" + subCaseId; 59 60 61 JarBuilder.build(jarName_verifier_test_tmp, "VerifierTest0", "VerifierTestA", 62 "VerifierTestB", "VerifierTestC", "VerifierTestD", "VerifierTestE", 63 "UnverifiableBase", "UnverifiableIntf", "UnverifiableIntfSub"); 64 JarBuilder.build(jarName_greet, "Greet"); 65 JarBuilder.build(jarName_hi, "Hi", "Hi$MyClass"); 66 67 File dir = new File(System.getProperty("test.classes", ".")); 68 File jarSrcFile = new File(dir, jarName_verifier_test_tmp + ".jar"); 69 File jarFile = new File(dir, jarName_verifier_test + ".jar"); 70 String jar = jarFile.getPath(); 71 72 if (!jarFile.exists() || jarFile.lastModified() < jarSrcFile.lastModified()) { 73 createTestJarFile(jarSrcFile, jarFile); 74 } else { 75 System.out.println("Already up-to-date: " + jarFile); 76 } 77 78 String noAppClasses[] = TestCommon.list(""); 79 String appClasses[] = TestCommon.list("UnverifiableBase", 80 "UnverifiableIntf", 81 "UnverifiableIntfSub", 82 "VerifierTestA", 83 "VerifierTestB", 84 "VerifierTestC", 85 "VerifierTestD", 86 "VerifierTestE", 87 "VerifierTest0"); 88 89 90 switch (subCaseId) { 91 case "0": testset_0(jar, noAppClasses, appClasses); return; 92 case "1A": testset_1(jar, noAppClasses, appClasses, Testset1Part.A); return; 93 case "1B": testset_1(jar, noAppClasses, appClasses, Testset1Part.B); return; 94 case "2": testset_2(jarName_greet, jarName_hi); return; 95 default: 96 throw new RuntimeException("Unknown option: " + subCaseId); 97 } 98 } 99 100 static void testset_0(String jar, String[] noAppClasses, String[] appClasses) throws Exception { 101 // Dumping should fail if the IgnoreUnverifiableClassesDuringDump 102 // option is not enabled. 103 OutputAnalyzer output = TestCommon.dump(jar, appClasses, 104 "-XX:+UnlockDiagnosticVMOptions", 105 "-XX:-IgnoreUnverifiableClassesDuringDump"); 106 output.shouldContain("Please remove the unverifiable classes"); 107 output.shouldHaveExitValue(1); 108 109 // By default, bad classes should be ignored during dumping. 110 TestCommon.testDump(jar, appClasses); 111 } 112 113 static void testset_1(String jar, String[] noAppClasses, String[] appClasses, Testset1Part part) 114 throws Exception 115 { 116 String config[][] = { 117 // {dump_list, dumptime_verification_setting, 118 // runtime_verification_setting, runtime_output}, 119 120 // Dump app/ext with -Xverify:remote 121 {"app", VFY_REMOTE, VFY_REMOTE, VFY_ERR}, 122 {"app", VFY_REMOTE, VFY_ALL, MAP_FAIL}, 123 {"app", VFY_REMOTE, VFY_NONE, ERR }, 124 // Dump app/ext with -Xverify:all 125 {"app", VFY_ALL, VFY_REMOTE, VFY_ERR }, 126 {"app", VFY_ALL, VFY_ALL, VFY_ERR }, 127 {"app", VFY_ALL, VFY_NONE, ERR }, 128 // Dump app/ext with -Xverify:none 129 {"app", VFY_NONE, VFY_REMOTE, MAP_FAIL}, 130 {"app", VFY_NONE, VFY_ALL, MAP_FAIL}, 131 {"app", VFY_NONE, VFY_NONE, ERR }, 132 // Dump sys only with -Xverify:remote 133 {"noApp", VFY_REMOTE, VFY_REMOTE, VFY_ERR}, 134 {"noApp", VFY_REMOTE, VFY_ALL, VFY_ERR}, 135 {"noApp", VFY_REMOTE, VFY_NONE, ERR}, 136 // Dump sys only with -Xverify:all 137 {"noApp", VFY_ALL, VFY_REMOTE, VFY_ERR}, 138 {"noApp", VFY_ALL, VFY_ALL, VFY_ERR}, 139 {"noApp", VFY_ALL, VFY_NONE, ERR}, 140 // Dump sys only with -Xverify:none 141 {"noApp", VFY_NONE, VFY_REMOTE, VFY_ERR}, 142 {"noApp", VFY_NONE, VFY_ALL, VFY_ERR}, 143 {"noApp", VFY_NONE, VFY_NONE, ERR}, 144 }; 145 146 int loop_start, loop_stop; 147 148 // Further break down testset_1 into two parts (to be invoked from VerifierTest_1A.java 149 // and VerifierTest_1B.java) to improve parallel test execution time. 150 switch (part) { 151 case A: 152 loop_start = 0; 153 loop_stop = 9; 154 break; 155 case B: 156 default: 157 assert part == Testset1Part.B; 158 loop_start = 9; 159 loop_stop = config.length; 160 break; 161 } 162 163 String prev_dump_setting = ""; 164 for (int i = loop_start; i < loop_stop; i ++) { 165 String dump_list[] = config[i][0].equals("app") ? appClasses : 166 noAppClasses; 167 String dump_setting = config[i][1]; 168 String runtime_setting = config[i][2]; 169 String runtime_output = config[i][3]; 170 System.out.println("Test case [" + i + "]: dumping " + config[i][0] + 171 " with " + dump_setting + 172 ", run with " + runtime_setting); 173 if (!dump_setting.equals(prev_dump_setting)) { 174 OutputAnalyzer dumpOutput = TestCommon.dump( 175 jar, dump_list, dump_setting, 176 // FIXME: the following options are for working around a GC 177 // issue - assert failure when dumping archive with the -Xverify:all 178 "-Xms256m", 179 "-Xmx256m"); 180 } 181 OutputAnalyzer runtimeOutput = TestCommon.execCommon( 182 "-cp", jar, 183 runtime_setting, 184 "VerifierTest0"); 185 try { 186 runtimeOutput.shouldContain(runtime_output); 187 } catch (RuntimeException re) { 188 // Check if the failure is due to archive mapping failure. 189 // If not, a RuntimeException will be thrown. 190 runtimeOutput.shouldContain("Unable to use shared archive"); 191 } 192 prev_dump_setting = dump_setting; 193 } 194 } 195 196 static void testset_2(String jarName_greet, String jarName_hi) throws Exception { 197 String appClasses[]; 198 String jar; 199 200 // The following section is for testing the scenarios where 201 // the classes are verifiable during dump time. 202 appClasses = TestCommon.list("Hi", 203 "Greet", 204 "Hi$MyClass"); 205 jar = TestCommon.getTestJar(jarName_hi + ".jar") + File.pathSeparator + 206 TestCommon.getTestJar(jarName_greet + ".jar"); 207 final String PASS_RESULT = "Hi, how are you?"; 208 String config2[][] = { 209 // {dump_list, dumptime_verification_setting, 210 // runtime_verification_setting, runtime_output}, 211 212 // Dump app/ext with -Xverify:remote 213 {"app", VFY_REMOTE, VFY_REMOTE, PASS_RESULT}, 214 {"app", VFY_REMOTE, VFY_ALL, MAP_FAIL}, 215 {"app", VFY_REMOTE, VFY_NONE, PASS_RESULT }, 216 // Dump app/ext with -Xverify:all 217 {"app", VFY_ALL, VFY_REMOTE, PASS_RESULT }, 218 {"app", VFY_ALL, VFY_ALL, PASS_RESULT }, 219 {"app", VFY_ALL, VFY_NONE, PASS_RESULT }, 220 // Dump app/ext with -Xverify:none 221 {"app", VFY_NONE, VFY_REMOTE, MAP_FAIL}, 222 {"app", VFY_NONE, VFY_ALL, MAP_FAIL}, 223 {"app", VFY_NONE, VFY_NONE, PASS_RESULT }, 224 }; 225 for (int i = 0; i < config2.length; i ++) { 226 // config2[i][0] is always set to "app" in this test 227 String dump_setting = config2[i][1]; 228 String runtime_setting = config2[i][2]; 229 String runtime_output = config2[i][3]; 230 System.out.println("Test case [" + i + "]: dumping " + config2[i][0] + 231 " with " + dump_setting + 232 ", run with " + runtime_setting); 233 OutputAnalyzer dumpOutput = TestCommon.dump( 234 jar, appClasses, dump_setting, 235 "-XX:+UnlockDiagnosticVMOptions", 236 // FIXME: the following options are for working around a GC 237 // issue - assert failure when dumping archive with the -Xverify:all 238 "-Xms256m", 239 "-Xmx256m"); 240 OutputAnalyzer runtimeOutput = TestCommon.execCommon( 241 "-cp", jar, 242 runtime_setting, 243 "Hi"); 244 try { 245 runtimeOutput.shouldContain(runtime_output); 246 } catch (RuntimeException re) { 247 // Check if the failure is due to archive mapping failure. 248 // If not, a RuntimeException will be thrown. 249 runtimeOutput.shouldContain("Unable to use shared archive"); 250 } 251 } 252 253 } 254 255 static void createTestJarFile(File jarSrcFile, File jarFile) throws Exception { 256 jarFile.delete(); 257 Files.copy(jarSrcFile.toPath(), jarFile.toPath()); 258 259 File dir = new File(System.getProperty("test.classes", ".")); 260 File outdir = new File(dir, "verifier_test_classes"); 261 outdir.mkdir(); 262 263 writeClassFile(new File(outdir, "UnverifiableBase.class"), makeUnverifiableBase()); 264 writeClassFile(new File(outdir, "UnverifiableIntf.class"), makeUnverifiableIntf()); 265 266 JarBuilder.update(jarFile.getPath(), outdir.getPath()); 267 } 268 269 static void writeClassFile(File file, byte bytecodes[]) throws Exception { 270 try (FileOutputStream fos = new FileOutputStream(file)) { 271 fos.write(bytecodes); 272 } 273 } 274 275 // This was obtained using JDK8: java jdk.internal.org.objectweb.asm.util.ASMifier tmpclasses/UnverifiableBase.class 276 static byte[] makeUnverifiableBase() throws Exception { 277 ClassWriter cw = new ClassWriter(0); 278 FieldVisitor fv; 279 MethodVisitor mv; 280 AnnotationVisitor av0; 281 282 cw.visit(V1_6, ACC_SUPER, "UnverifiableBase", null, "java/lang/Object", null); 283 { 284 fv = cw.visitField(ACC_FINAL + ACC_STATIC, "x", "LVerifierTest;", null, null); 285 fv.visitEnd(); 286 } 287 { 288 mv = cw.visitMethod(0, "<init>", "()V", null, null); 289 mv.visitCode(); 290 mv.visitVarInsn(ALOAD, 0); 291 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 292 mv.visitInsn(RETURN); 293 mv.visitMaxs(1, 1); 294 mv.visitEnd(); 295 } 296 { 297 mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null); 298 mv.visitCode(); 299 //WAS mv.visitTypeInsn(NEW, "VerifierTest"); 300 mv.visitTypeInsn(NEW, "java/lang/Object"); 301 mv.visitInsn(DUP); 302 mv.visitMethodInsn(INVOKESPECIAL, "VerifierTest0", "<init>", "()V", false); 303 mv.visitFieldInsn(PUTSTATIC, "UnverifiableBase", "x", "LVerifierTest;"); 304 mv.visitInsn(RETURN); 305 mv.visitMaxs(2, 0); 306 mv.visitEnd(); 307 } 308 cw.visitEnd(); 309 310 return cw.toByteArray(); 311 } 312 313 // This was obtained using JDK8: java jdk.internal.org.objectweb.asm.util.ASMifier tmpclasses/UnverifiableIntf.class 314 static byte[] makeUnverifiableIntf() throws Exception { 315 ClassWriter cw = new ClassWriter(0); 316 FieldVisitor fv; 317 MethodVisitor mv; 318 AnnotationVisitor av0; 319 320 cw.visit(V1_6, ACC_ABSTRACT + ACC_INTERFACE, "UnverifiableIntf", null, "java/lang/Object", null); 321 322 { 323 fv = cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "x", "LVerifierTest0;", null, null); 324 fv.visitEnd(); 325 } 326 { 327 mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null); 328 mv.visitCode(); 329 //WAS mv.visitTypeInsn(NEW, "VerifierTest"); 330 mv.visitTypeInsn(NEW, "java/lang/Object"); 331 mv.visitInsn(DUP); 332 mv.visitMethodInsn(INVOKESPECIAL, "VerifierTest0", "<init>", "()V", false); 333 mv.visitFieldInsn(PUTSTATIC, "UnverifiableIntf", "x", "LVerifierTest0;"); 334 mv.visitInsn(RETURN); 335 mv.visitMaxs(2, 0); 336 mv.visitEnd(); 337 } 338 cw.visitEnd(); 339 340 return cw.toByteArray(); 341 } 342 343 }