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