1 /* 2 * Copyright (c) 2022, 2025, 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 * @summary Testing ClassFile Verifier. 27 * @bug 8333812 8361526 28 * @run junit VerifierSelfTest 29 * @run junit/othervm --enable-preview VerifierSelfTest 30 */ 31 import java.io.IOException; 32 import java.lang.classfile.constantpool.PoolEntry; 33 import java.lang.constant.ClassDesc; 34 35 import static java.lang.classfile.ClassFile.ACC_STATIC; 36 import static java.lang.classfile.ClassFile.JAVA_8_VERSION; 37 import static java.lang.constant.ConstantDescs.*; 38 39 import java.lang.constant.MethodTypeDesc; 40 import java.lang.invoke.MethodHandleInfo; 41 import java.lang.invoke.MethodHandles; 42 import java.net.URI; 43 import java.nio.file.FileSystem; 44 import java.nio.file.FileSystems; 45 import java.nio.file.Files; 46 import java.nio.file.Path; 47 import java.util.ArrayList; 48 import java.util.Arrays; 49 import java.util.LinkedList; 50 import java.util.List; 51 import java.util.Map; 52 import java.util.Optional; 53 import java.util.stream.Collectors; 54 import java.util.stream.Stream; 55 import java.lang.classfile.*; 56 import java.lang.classfile.attribute.*; 57 import jdk.internal.classfile.components.ClassPrinter; 58 import java.lang.classfile.constantpool.Utf8Entry; 59 import java.lang.constant.ModuleDesc; 60 61 import jdk.internal.classfile.impl.BufWriterImpl; 62 import jdk.internal.classfile.impl.DirectClassBuilder; 63 import jdk.internal.classfile.impl.UnboundAttribute; 64 import org.junit.jupiter.api.Test; 65 import org.junit.jupiter.params.ParameterizedTest; 66 import org.junit.jupiter.params.provider.Arguments; 67 import org.junit.jupiter.params.provider.MethodSource; 68 69 import static org.junit.jupiter.api.Assertions.*; 70 71 class VerifierSelfTest { 72 73 private static final FileSystem JRT = FileSystems.getFileSystem(URI.create("jrt:/")); 74 75 @Test 76 void testVerify() throws IOException { 77 Stream.of( 78 Files.walk(JRT.getPath("modules/java.base")), 79 Files.walk(JRT.getPath("modules"), 2).filter(p -> p.endsWith("module-info.class"))) 80 .flatMap(p -> p) 81 .filter(p -> Files.isRegularFile(p) && p.toString().endsWith(".class")).forEach(path -> { 82 try { 83 ClassFile.of().verify(path); 84 } catch (IOException e) { 85 throw new AssertionError(e); 86 } 87 }); 88 } 89 90 @Test 91 void testFailed() throws IOException { 92 Path path = FileSystems.getFileSystem(URI.create("jrt:/")).getPath("modules/java.base/java/util/HashMap.class"); 93 var cc = ClassFile.of(ClassFile.ClassHierarchyResolverOption.of( 94 className -> ClassHierarchyResolver.ClassHierarchyInfo.ofClass(null))); 95 var classModel = cc.parse(path); 96 byte[] brokenClassBytes = cc.transformClass(classModel, 97 (clb, cle) -> { 98 if (cle instanceof MethodModel mm) { 99 clb.transformMethod(mm, (mb, me) -> { 100 if (me instanceof CodeModel cm) { 101 mb.withCode(cob -> cm.forEach(cob)); 102 } 103 else 104 mb.with(me); 105 }); 106 } 107 else 108 clb.with(cle); 109 }); 110 StringBuilder sb = new StringBuilder(); 111 if (ClassFile.of().verify(brokenClassBytes).isEmpty()) { 112 throw new AssertionError("expected verification failure"); 113 } 114 } 115 116 @Test 117 void testInvalidAttrLocation() { 118 var cc = ClassFile.of(); 119 var bytes = cc.build(ClassDesc.of("InvalidAttrLocationClass"), cb -> 120 ((DirectClassBuilder)cb).writeAttribute(new UnboundAttribute.AdHocAttribute<LocalVariableTableAttribute>(Attributes.localVariableTable()) { 121 @Override 122 public void writeBody(BufWriterImpl b) { 123 b.writeU2(0); 124 } 125 126 @Override 127 public Utf8Entry attributeName() { 128 return cb.constantPool().utf8Entry(Attributes.NAME_LOCAL_VARIABLE_TABLE); 129 } 130 })); 131 assertTrue(cc.verify(bytes).stream().anyMatch(e -> e.getMessage().contains("Invalid LocalVariableTable attribute location"))); 132 } 133 134 @Test 135 void testInvalidClassNameEntry() { 136 var cc = ClassFile.of(); 137 var bytes = cc.parse(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, 138 0, 0, 0, 0, 0, 2, PoolEntry.TAG_INTEGER, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); 139 assertTrue(cc.verify(bytes).stream().anyMatch(e -> e.getMessage().contains("expected ClassEntry"))); 140 } 141 142 @Test 143 void testParserVerification() { 144 var cc = ClassFile.of(); 145 var cd_test = ClassDesc.of("ParserVerificationTestClass"); 146 var indexes = new Object[9]; 147 var clm = cc.parse(cc.build(cd_test, clb -> { 148 clb.withFlags(ClassFile.ACC_INTERFACE | ClassFile.ACC_FINAL); 149 var cp = clb.constantPool(); 150 var ce_valid = cp.classEntry(cd_test); 151 var ce_invalid = cp.classEntry(cp.utf8Entry("invalid.class.name")); 152 indexes[0] = ce_invalid.index(); 153 var nate_invalid_field = cp.nameAndTypeEntry("field;", CD_int); 154 var nate_invalid_method = cp.nameAndTypeEntry("method;", MTD_void); 155 var bsme = cp.bsmEntry(BSM_INVOKE, List.of()); 156 indexes[1] = cp.methodTypeEntry(cp.utf8Entry("invalid method type")).index(); 157 indexes[2] = cp.constantDynamicEntry(bsme, nate_invalid_method).index(); 158 indexes[3] = cp.invokeDynamicEntry(bsme, nate_invalid_field).index(); 159 indexes[4] = cp.fieldRefEntry(ce_invalid, nate_invalid_method).index(); 160 indexes[5] = cp.methodRefEntry(ce_invalid, nate_invalid_field).index(); 161 indexes[6] = cp.interfaceMethodRefEntry(ce_invalid, nate_invalid_field).index(); 162 indexes[7] = cp.methodHandleEntry(MethodHandleInfo.REF_getField, cp.methodRefEntry(cd_test, "method", MTD_void)).index(); 163 indexes[8] = cp.methodHandleEntry(MethodHandleInfo.REF_invokeVirtual, cp.fieldRefEntry(cd_test, "field", CD_int)).index(); 164 patch(clb, 165 CompilationIDAttribute.of("12345"), 166 DeprecatedAttribute.of(), 167 EnclosingMethodAttribute.of(cd_test, Optional.empty(), Optional.empty()), 168 InnerClassesAttribute.of(InnerClassInfo.of(cd_test, Optional.of(cd_test), Optional.of("inner"), 0)), 169 ModuleAttribute.of(ModuleDesc.of("m"), mab -> {}), 170 ModuleHashesAttribute.of("alg", List.of()), 171 ModuleMainClassAttribute.of(cd_test), 172 ModulePackagesAttribute.of(), 173 ModuleResolutionAttribute.of(0), 174 ModuleTargetAttribute.of("t"), 175 NestHostAttribute.of(cd_test), 176 NestMembersAttribute.ofSymbols(cd_test), 177 PermittedSubclassesAttribute.ofSymbols(cd_test), 178 RecordAttribute.of(RecordComponentInfo.of("c", CD_String, patch( 179 SignatureAttribute.of(Signature.of(CD_String)), 180 RuntimeVisibleAnnotationsAttribute.of(), 181 RuntimeInvisibleAnnotationsAttribute.of(), 182 RuntimeVisibleTypeAnnotationsAttribute.of(), 183 RuntimeInvisibleTypeAnnotationsAttribute.of()))), 184 RuntimeVisibleAnnotationsAttribute.of(), 185 RuntimeInvisibleAnnotationsAttribute.of(), 186 RuntimeVisibleTypeAnnotationsAttribute.of(), 187 RuntimeInvisibleTypeAnnotationsAttribute.of(), 188 SignatureAttribute.of(ClassSignature.of(Signature.ClassTypeSig.of(cd_test))), 189 SourceDebugExtensionAttribute.of("sde".getBytes()), 190 SourceFileAttribute.of("ParserVerificationTestClass.java"), 191 SourceIDAttribute.of("sID"), 192 SyntheticAttribute.of()) 193 .withInterfaceSymbols(CD_List, CD_List) 194 .withField("f", CD_String, fb -> patch(fb, 195 ConstantValueAttribute.of(0), 196 DeprecatedAttribute.of(), 197 RuntimeVisibleAnnotationsAttribute.of(), 198 RuntimeInvisibleAnnotationsAttribute.of(), 199 RuntimeVisibleTypeAnnotationsAttribute.of(), 200 RuntimeInvisibleTypeAnnotationsAttribute.of(), 201 SignatureAttribute.of(Signature.of(CD_String)), 202 SyntheticAttribute.of())) 203 .withField("/", CD_int, 0) 204 .withField("/", CD_int, 0) 205 .withMethod("m", MTD_void, ClassFile.ACC_ABSTRACT | ClassFile.ACC_STATIC, mb -> patch(mb, 206 AnnotationDefaultAttribute.of(AnnotationValue.ofInt(0)), 207 DeprecatedAttribute.of(), 208 ExceptionsAttribute.ofSymbols(CD_Exception), 209 MethodParametersAttribute.of(MethodParameterInfo.ofParameter(Optional.empty(), 0)), 210 RuntimeVisibleAnnotationsAttribute.of(), 211 RuntimeInvisibleAnnotationsAttribute.of(), 212 RuntimeVisibleParameterAnnotationsAttribute.of(List.of()), 213 RuntimeInvisibleParameterAnnotationsAttribute.of(List.of()), 214 SignatureAttribute.of(MethodSignature.of(MTD_void)), 215 SyntheticAttribute.of()) 216 .withCode(cob -> 217 cob.iconst_0() 218 .ifThen(CodeBuilder::nop) 219 .return_() 220 .with(new CloneAttribute(CharacterRangeTableAttribute.of(List.of()))) 221 .with(new CloneAttribute(LineNumberTableAttribute.of(List.of()))) 222 .with(new CloneAttribute(LocalVariableTableAttribute.of(List.of()))) 223 .with(new CloneAttribute(LocalVariableTypeTableAttribute.of(List.of()))))) 224 .withMethod("<>", MTD_void, ClassFile.ACC_NATIVE, mb -> {}) 225 .withMethod("<>", MTD_void, ClassFile.ACC_NATIVE, mb -> {}) 226 .withMethod(INIT_NAME, MTD_void, 0, mb -> {}) 227 .withMethod(CLASS_INIT_NAME, MTD_void, 0, mb -> {}); 228 })); 229 var found = cc.verify(clm).stream().map(VerifyError::getMessage).collect(Collectors.toCollection(LinkedList::new)); 230 var expected = """ 231 Invalid class name: invalid.class.name at constant pool index %1$d in class ParserVerificationTestClass 232 Bad method descriptor: invalid method type at constant pool index %2$d in class ParserVerificationTestClass 233 not a valid reference type descriptor: ()V at constant pool index %3$d in class ParserVerificationTestClass 234 Bad method descriptor: I at constant pool index %4$d in class ParserVerificationTestClass 235 not a valid reference type descriptor: ()V at constant pool index %5$d in class ParserVerificationTestClass 236 Invalid class name: invalid.class.name at constant pool index %5$d in class ParserVerificationTestClass 237 Illegal field name method; in class ParserVerificationTestClass at constant pool index %5$d in class ParserVerificationTestClass 238 Bad method descriptor: I at constant pool index %6$d in class ParserVerificationTestClass 239 Invalid class name: invalid.class.name at constant pool index %6$d in class ParserVerificationTestClass 240 Illegal method name field; in class ParserVerificationTestClass at constant pool index %6$d in class ParserVerificationTestClass 241 Bad method descriptor: I at constant pool index %7$d in class ParserVerificationTestClass 242 Invalid class name: invalid.class.name at constant pool index %7$d in class ParserVerificationTestClass 243 Illegal method name field; in class ParserVerificationTestClass at constant pool index %7$d in class ParserVerificationTestClass 244 not a valid reference type descriptor: ()V at constant pool index %8$d in class ParserVerificationTestClass 245 Bad method descriptor: I at constant pool index %9$d in class ParserVerificationTestClass 246 Duplicate interface List in class ParserVerificationTestClass 247 Illegal field name / in class ParserVerificationTestClass 248 Duplicate field name / with signature I in class ParserVerificationTestClass 249 Illegal field name / in class ParserVerificationTestClass 250 Illegal method name <> in class ParserVerificationTestClass 251 Duplicate method name <> with signature ()V in class ParserVerificationTestClass 252 Illegal method name <> in class ParserVerificationTestClass 253 Interface cannot have a method named <init> in class ParserVerificationTestClass 254 Method <clinit> is not static in class ParserVerificationTestClass 255 Multiple CompilationID attributes in class ParserVerificationTestClass 256 Wrong CompilationID attribute length in class ParserVerificationTestClass 257 Wrong Deprecated attribute length in class ParserVerificationTestClass 258 Multiple EnclosingMethod attributes in class ParserVerificationTestClass 259 Wrong EnclosingMethod attribute length in class ParserVerificationTestClass 260 Class is both outer and inner class in class ParserVerificationTestClass 261 Multiple InnerClasses attributes in class ParserVerificationTestClass 262 Class is both outer and inner class in class ParserVerificationTestClass 263 Wrong InnerClasses attribute length in class ParserVerificationTestClass 264 Multiple Module attributes in class ParserVerificationTestClass 265 Wrong Module attribute length in class ParserVerificationTestClass 266 Multiple ModuleHashes attributes in class ParserVerificationTestClass 267 Wrong ModuleHashes attribute length in class ParserVerificationTestClass 268 Multiple ModuleMainClass attributes in class ParserVerificationTestClass 269 Wrong ModuleMainClass attribute length in class ParserVerificationTestClass 270 Multiple ModulePackages attributes in class ParserVerificationTestClass 271 Wrong ModulePackages attribute length in class ParserVerificationTestClass 272 Multiple ModuleResolution attributes in class ParserVerificationTestClass 273 Wrong ModuleResolution attribute length in class ParserVerificationTestClass 274 Multiple ModuleTarget attributes in class ParserVerificationTestClass 275 Wrong ModuleTarget attribute length in class ParserVerificationTestClass 276 Multiple NestHost attributes in class ParserVerificationTestClass 277 Wrong NestHost attribute length in class ParserVerificationTestClass 278 Conflicting NestHost and NestMembers attributes in class ParserVerificationTestClass 279 Multiple NestMembers attributes in class ParserVerificationTestClass 280 Conflicting NestHost and NestMembers attributes in class ParserVerificationTestClass 281 Wrong NestMembers attribute length in class ParserVerificationTestClass 282 PermittedSubclasses attribute in final class ParserVerificationTestClass 283 Multiple PermittedSubclasses attributes in class ParserVerificationTestClass 284 PermittedSubclasses attribute in final class ParserVerificationTestClass 285 Wrong PermittedSubclasses attribute length in class ParserVerificationTestClass 286 Multiple Record attributes in class ParserVerificationTestClass 287 Wrong Record attribute length in class ParserVerificationTestClass 288 Multiple RuntimeVisibleAnnotations attributes in class ParserVerificationTestClass 289 Wrong RuntimeVisibleAnnotations attribute length in class ParserVerificationTestClass 290 Multiple RuntimeInvisibleAnnotations attributes in class ParserVerificationTestClass 291 Wrong RuntimeInvisibleAnnotations attribute length in class ParserVerificationTestClass 292 Multiple RuntimeVisibleTypeAnnotations attributes in class ParserVerificationTestClass 293 Wrong RuntimeVisibleTypeAnnotations attribute length in class ParserVerificationTestClass 294 Multiple RuntimeInvisibleTypeAnnotations attributes in class ParserVerificationTestClass 295 Wrong RuntimeInvisibleTypeAnnotations attribute length in class ParserVerificationTestClass 296 Multiple Signature attributes in class ParserVerificationTestClass 297 Wrong Signature attribute length in class ParserVerificationTestClass 298 Multiple SourceDebugExtension attributes in class ParserVerificationTestClass 299 Multiple SourceFile attributes in class ParserVerificationTestClass 300 Wrong SourceFile attribute length in class ParserVerificationTestClass 301 Multiple SourceID attributes in class ParserVerificationTestClass 302 Wrong SourceID attribute length in class ParserVerificationTestClass 303 Wrong Synthetic attribute length in class ParserVerificationTestClass 304 Bad constant value type in field ParserVerificationTestClass.f 305 Multiple ConstantValue attributes in field ParserVerificationTestClass.f 306 Bad constant value type in field ParserVerificationTestClass.f 307 Wrong ConstantValue attribute length in field ParserVerificationTestClass.f 308 Wrong Deprecated attribute length in field ParserVerificationTestClass.f 309 Multiple RuntimeVisibleAnnotations attributes in field ParserVerificationTestClass.f 310 Wrong RuntimeVisibleAnnotations attribute length in field ParserVerificationTestClass.f 311 Multiple RuntimeInvisibleAnnotations attributes in field ParserVerificationTestClass.f 312 Wrong RuntimeInvisibleAnnotations attribute length in field ParserVerificationTestClass.f 313 Multiple RuntimeVisibleTypeAnnotations attributes in field ParserVerificationTestClass.f 314 Wrong RuntimeVisibleTypeAnnotations attribute length in field ParserVerificationTestClass.f 315 Multiple RuntimeInvisibleTypeAnnotations attributes in field ParserVerificationTestClass.f 316 Wrong RuntimeInvisibleTypeAnnotations attribute length in field ParserVerificationTestClass.f 317 Multiple Signature attributes in field ParserVerificationTestClass.f 318 Wrong Signature attribute length in field ParserVerificationTestClass.f 319 Wrong Synthetic attribute length in field ParserVerificationTestClass.f 320 Multiple AnnotationDefault attributes in method ParserVerificationTestClass::m() 321 Wrong AnnotationDefault attribute length in method ParserVerificationTestClass::m() 322 Wrong Deprecated attribute length in method ParserVerificationTestClass::m() 323 Multiple Exceptions attributes in method ParserVerificationTestClass::m() 324 Wrong Exceptions attribute length in method ParserVerificationTestClass::m() 325 Multiple MethodParameters attributes in method ParserVerificationTestClass::m() 326 Wrong MethodParameters attribute length in method ParserVerificationTestClass::m() 327 Multiple RuntimeVisibleAnnotations attributes in method ParserVerificationTestClass::m() 328 Wrong RuntimeVisibleAnnotations attribute length in method ParserVerificationTestClass::m() 329 Multiple RuntimeInvisibleAnnotations attributes in method ParserVerificationTestClass::m() 330 Wrong RuntimeInvisibleAnnotations attribute length in method ParserVerificationTestClass::m() 331 Multiple RuntimeVisibleParameterAnnotations attributes in method ParserVerificationTestClass::m() 332 Wrong RuntimeVisibleParameterAnnotations attribute length in method ParserVerificationTestClass::m() 333 Multiple RuntimeInvisibleParameterAnnotations attributes in method ParserVerificationTestClass::m() 334 Wrong RuntimeInvisibleParameterAnnotations attribute length in method ParserVerificationTestClass::m() 335 Multiple Signature attributes in method ParserVerificationTestClass::m() 336 Wrong Signature attribute length in method ParserVerificationTestClass::m() 337 Wrong Synthetic attribute length in method ParserVerificationTestClass::m() 338 Code attribute in native or abstract method ParserVerificationTestClass::m() 339 Wrong CharacterRangeTable attribute length in Code attribute for method ParserVerificationTestClass::m() 340 Wrong LineNumberTable attribute length in Code attribute for method ParserVerificationTestClass::m() 341 Wrong LocalVariableTable attribute length in Code attribute for method ParserVerificationTestClass::m() 342 Wrong LocalVariableTypeTable attribute length in Code attribute for method ParserVerificationTestClass::m() 343 Multiple Signature attributes in Record component c of class ParserVerificationTestClass 344 Wrong Signature attribute length in Record component c of class ParserVerificationTestClass 345 Multiple RuntimeVisibleAnnotations attributes in Record component c of class ParserVerificationTestClass 346 Wrong RuntimeVisibleAnnotations attribute length in Record component c of class ParserVerificationTestClass 347 Multiple RuntimeInvisibleAnnotations attributes in Record component c of class ParserVerificationTestClass 348 Wrong RuntimeInvisibleAnnotations attribute length in Record component c of class ParserVerificationTestClass 349 Multiple RuntimeVisibleTypeAnnotations attributes in Record component c of class ParserVerificationTestClass 350 Wrong RuntimeVisibleTypeAnnotations attribute length in Record component c of class ParserVerificationTestClass 351 Multiple RuntimeInvisibleTypeAnnotations attributes in Record component c of class ParserVerificationTestClass 352 Wrong RuntimeInvisibleTypeAnnotations attribute length in Record component c of class ParserVerificationTestClass 353 Multiple Signature attributes in Record component c of class ParserVerificationTestClass 354 Wrong Signature attribute length in Record component c of class ParserVerificationTestClass 355 Multiple RuntimeVisibleAnnotations attributes in Record component c of class ParserVerificationTestClass 356 Wrong RuntimeVisibleAnnotations attribute length in Record component c of class ParserVerificationTestClass 357 Multiple RuntimeInvisibleAnnotations attributes in Record component c of class ParserVerificationTestClass 358 Wrong RuntimeInvisibleAnnotations attribute length in Record component c of class ParserVerificationTestClass 359 Multiple RuntimeVisibleTypeAnnotations attributes in Record component c of class ParserVerificationTestClass 360 Wrong RuntimeVisibleTypeAnnotations attribute length in Record component c of class ParserVerificationTestClass 361 Multiple RuntimeInvisibleTypeAnnotations attributes in Record component c of class ParserVerificationTestClass 362 Wrong RuntimeInvisibleTypeAnnotations attribute length in Record component c of class ParserVerificationTestClass 363 Missing Code attribute in ParserVerificationTestClass::<init>() @0 364 Missing Code attribute in ParserVerificationTestClass::<clinit>() @0 365 """.formatted(indexes).lines().filter(exp -> !found.remove(exp)).toList(); 366 if (!found.isEmpty() || !expected.isEmpty()) { 367 ClassPrinter.toYaml(clm, ClassPrinter.Verbosity.TRACE_ALL, System.out::print); 368 fail(""" 369 370 Expected: 371 %s 372 373 Found: 374 %s 375 """.formatted(expected.stream().collect(Collectors.joining("\n ")), found.stream().collect(Collectors.joining("\n ")))); 376 } 377 } 378 379 private static class CloneAttribute extends CustomAttribute<CloneAttribute> { 380 CloneAttribute(Attribute a) { 381 super(new AttributeMapper<CloneAttribute>(){ 382 @Override 383 public String name() { 384 return a.attributeName().stringValue(); 385 } 386 387 @Override 388 public CloneAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { 389 throw new UnsupportedOperationException(); 390 } 391 392 @Override 393 public void writeAttribute(BufWriter buf, CloneAttribute attr) { 394 int start = buf.size(); 395 a.attributeMapper().writeAttribute(buf, a); 396 buf.writeU1(0); //writes additional byte to the attribute payload 397 buf.patchInt(start + 2, 4, buf.size() - start - 6); 398 } 399 400 @Override 401 public AttributeMapper.AttributeStability stability() { 402 return a.attributeMapper().stability(); 403 } 404 }); 405 } 406 } 407 408 private static <B extends ClassFileBuilder> B patch(B b, Attribute... attrs) { 409 for (var a : attrs) { 410 b.with(a).with(new CloneAttribute(a)); 411 } 412 return b; 413 } 414 415 private static List<Attribute<?>> patch(Attribute... attrs) { 416 var lst = new ArrayList<Attribute<?>>(attrs.length * 2); 417 for (var a : attrs) { 418 lst.add(a); 419 lst.add(new CloneAttribute(a)); 420 } 421 return lst; 422 } 423 424 @Test // JDK-8350029 425 void testInvokeSpecialInterfacePatch() { 426 var runClass = ClassDesc.of("Run"); 427 var testClass = ClassDesc.of("Test"); 428 var runnableClass = Runnable.class.describeConstable().orElseThrow(); 429 var chr = ClassHierarchyResolver.of(List.of(), Map.of(runClass, CD_Object)) 430 .orElse(ClassHierarchyResolver.defaultResolver()).cached(); 431 var context = ClassFile.of(ClassFile.ClassHierarchyResolverOption.of(chr)); 432 433 for (var isInterface : new boolean[] {true, false}) { 434 var bytes = context.build(testClass, clb -> clb 435 .withVersion(JAVA_8_VERSION, 0) 436 .withSuperclass(runClass) 437 .withMethodBody("test", MethodTypeDesc.of(CD_void, testClass), ACC_STATIC, cob -> cob 438 .aload(0) 439 .invokespecial(runnableClass, "run", MTD_void, isInterface) 440 .return_())); 441 var errors = context.verify(bytes); 442 assertNotEquals(List.of(), errors, "invokespecial, isInterface = " + isInterface); 443 assertTrue(errors.getFirst().getMessage().contains("interface method to invoke is not in a direct superinterface"), errors.getFirst().getMessage()); 444 } 445 } 446 447 enum ComparisonInstruction { 448 IF_ACMPEQ(Opcode.IF_ACMPEQ, 2), 449 IF_ACMPNE(Opcode.IF_ACMPNE, 2), 450 IFNONNULL(Opcode.IFNONNULL, 1), 451 IFNULL(Opcode.IFNULL, 1); 452 final Opcode opcode; 453 final int argCount; 454 ComparisonInstruction(Opcode opcode, int argCount) { 455 this.opcode = opcode; 456 this.argCount = argCount; 457 } 458 } 459 460 enum UninitializeKind { 461 UNINITIALIZED, UNINITIALIZED_THIS 462 } 463 464 @ParameterizedTest 465 @MethodSource("uninitializedInBytecodeClasses") 466 public void testUninitializedInComparisons(ComparisonInstruction inst, UninitializeKind kind) throws Throwable { 467 var bytes = ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS).build(ClassDesc.of("Test"), clb -> clb 468 .withMethodBody(INIT_NAME, MTD_void, 0, cob -> { 469 StackMapFrameInfo.VerificationTypeInfo uninitializeInfo; 470 if (kind == UninitializeKind.UNINITIALIZED) { 471 uninitializeInfo = StackMapFrameInfo.UninitializedVerificationTypeInfo.of(cob.newBoundLabel()); 472 cob.new_(CD_Object); 473 } else { 474 uninitializeInfo = StackMapFrameInfo.SimpleVerificationTypeInfo.UNINITIALIZED_THIS; 475 cob.aload(0); 476 } 477 478 // Stack: uninitializeInfo 479 for (int i = 0; i < inst.argCount; i++) { 480 cob.dup(); 481 } 482 var dest = cob.newLabel(); 483 cob.branch(inst.opcode, dest) 484 .nop() 485 .labelBinding(dest) 486 .with(StackMapTableAttribute.of(List.of(StackMapFrameInfo.of(dest, 487 List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.UNINITIALIZED_THIS), 488 List.of(uninitializeInfo))))) 489 .invokespecial(CD_Object, INIT_NAME, MTD_void); 490 if (kind == UninitializeKind.UNINITIALIZED) { 491 // still need to call super constructor 492 cob.aload(0) 493 .invokespecial(CD_Object, INIT_NAME, MTD_void); 494 } 495 cob.return_(); 496 })); 497 var errors = ClassFile.of().verify(bytes); 498 assertNotEquals(List.of(), errors, () -> errors + " : " + ClassFile.of().parse(bytes).toDebugString()); 499 var lookup = MethodHandles.lookup(); 500 assertThrows(VerifyError.class, () -> lookup.defineHiddenClass(bytes, true)); // force JVM verification 501 } 502 503 public static Stream<Arguments> uninitializedInBytecodeClasses() { 504 return Arrays.stream(ComparisonInstruction.values()) 505 .mapMulti((inst, sink) -> { 506 for (var kind : UninitializeKind.values()) { 507 sink.accept(Arguments.of(inst, kind)); 508 } 509 }); 510 } 511 }