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