diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index 5b2378e0a7a..ceccdce16fd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -311,6 +311,13 @@ public final class DirectCodeBuilder buf.setLabelContext(DirectCodeBuilder.this); int codeLength = curPc(); + if (codeLength == 0 || codeLength >= 65536) { + throw new IllegalArgumentException(String.format( + "Code length %d is outside the allowed range in %s%s", + codeLength, + methodInfo.methodName().stringValue(), + methodInfo.methodTypeSymbol().displayDescriptor())); + } int maxStack, maxLocals; Attribute stackMapAttr; boolean canReuseStackmaps = codeAndExceptionsMatch(codeLength); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index 9fc90a24448..7d304fd73f6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -194,6 +194,9 @@ public final class SplitConstantPool implements ConstantPoolBuilder { @Override public void writeTo(BufWriter buf) { int writeFrom = 1; + if (entryCount() >= 65536) { + throw new IllegalArgumentException(String.format("Constant pool is too large %d", entryCount())); + } buf.writeU2(entryCount()); if (parent != null && buf.constantPool().canWriteDirect(this)) { parent.writeConstantPoolEntries(buf); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java index ea3baa06471..14be6c3e675 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,7 @@ public final class VerifierImpl { JVM_CONSTANT_Package = 20, JVM_CONSTANT_ExternalMax = 20; -static final char JVM_SIGNATURE_SPECIAL = '<', + static final char JVM_SIGNATURE_SPECIAL = '<', JVM_SIGNATURE_ARRAY = '[', JVM_SIGNATURE_BYTE = 'B', JVM_SIGNATURE_CHAR = 'C', @@ -102,6 +102,7 @@ static final char JVM_SIGNATURE_SPECIAL = '<', static final int STACKMAP_ATTRIBUTE_MAJOR_VERSION = 50; static final int INVOKEDYNAMIC_MAJOR_VERSION = 51; static final int NOFAILOVER_MAJOR_VERSION = 51; + static final int MAX_CODE_SIZE = 65535; public static List verify(ClassModel classModel, Consumer logger) { return verify(classModel, ClassHierarchyResolver.DEFAULT_CLASS_HIERARCHY_RESOLVER, logger); @@ -299,6 +300,9 @@ static final char JVM_SIGNATURE_SPECIAL = '<', VerificationType return_type = current_frame.set_locals_from_arg(m, current_type()); int stackmap_index = 0; int code_length = m.codeLength(); + if (code_length < 1 || code_length > MAX_CODE_SIZE) { + verifyError(String.format("Invalid method Code length %d", code_length)); + } var code = ByteBuffer.wrap(_method.codeArray(), 0, _method.codeLength()); byte[] code_data = generate_code_data(code, code_length); int ex_minmax[] = new int[] {code_length, -1}; diff --git a/test/jdk/jdk/classfile/BuilderBlockTest.java b/test/jdk/jdk/classfile/BuilderBlockTest.java index cff73b8d332..45b8904eae0 100644 --- a/test/jdk/jdk/classfile/BuilderBlockTest.java +++ b/test/jdk/jdk/classfile/BuilderBlockTest.java @@ -255,6 +255,7 @@ class BuilderBlockTest { assertEquals(slot1, 4); assertEquals(slot2, 5); assertEquals(slot3, 7); + xb.return_(); })); }); } @@ -275,6 +276,7 @@ class BuilderBlockTest { }); int slot4 = xb.allocateLocal(TypeKind.IntType); assertEquals(slot4, 4); + xb.return_(); })); }); } diff --git a/test/jdk/jdk/classfile/BuilderParamTest.java b/test/jdk/jdk/classfile/BuilderParamTest.java index 4d744e67538..ca49a88005d 100644 --- a/test/jdk/jdk/classfile/BuilderParamTest.java +++ b/test/jdk/jdk/classfile/BuilderParamTest.java @@ -52,6 +52,7 @@ class BuilderParamTest { assertEquals(xb.parameterSlot(0), 1); assertEquals(xb.parameterSlot(1), 2); assertEquals(xb.parameterSlot(2), 4); + xb.return_(); })); }); @@ -61,6 +62,7 @@ class BuilderParamTest { assertEquals(xb.parameterSlot(0), 0); assertEquals(xb.parameterSlot(1), 1); assertEquals(xb.parameterSlot(2), 3); + xb.return_(); })); }); } diff --git a/test/jdk/jdk/classfile/LimitsTest.java b/test/jdk/jdk/classfile/LimitsTest.java index ec33f9f27af..83b4c37cc56 100644 --- a/test/jdk/jdk/classfile/LimitsTest.java +++ b/test/jdk/jdk/classfile/LimitsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,8 +30,10 @@ */ import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; +import java.lang.constant.MethodTypeDesc; import jdk.internal.classfile.Classfile; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; class LimitsTest { @@ -44,4 +46,29 @@ class LimitsTest { }); } + @Test + void testCPOverLimit() { + assertThrows(IllegalArgumentException.class, () -> Classfile.build(ClassDesc.of("BigClass"), cb -> { + for (int i = 1; i < 66000; i++) { + cb.withField("field" + i, ConstantDescs.CD_int, fb -> {}); + } + })); + } + + @Test + void testCodeOverLimit() { + assertThrows(IllegalArgumentException.class, () -> Classfile.build(ClassDesc.of("BigClass"), cb -> cb.withMethodBody( + "bigMethod", MethodTypeDesc.of(ConstantDescs.CD_void), 0, cob -> { + for (int i = 0; i < 65535; i++) { + cob.nop(); + } + cob.return_(); + }))); + } + + @Test + void testEmptyCode() { + assertThrows(IllegalArgumentException.class, () -> Classfile.build(ClassDesc.of("EmptyClass"), cb -> cb.withMethodBody( + "emptyMethod", MethodTypeDesc.of(ConstantDescs.CD_void), 0, cob -> {}))); + } }