diff --git a/asm/src/main/java/org/objectweb/asm/ByteVector.java b/asm/src/main/java/org/objectweb/asm/ByteVector.java
index 425324f2..d444fd2a 100644
--- a/asm/src/main/java/org/objectweb/asm/ByteVector.java
+++ b/asm/src/main/java/org/objectweb/asm/ByteVector.java
@@ -242,7 +242,7 @@ public ByteVector putLong(final long longValue) {
public ByteVector putUTF8(final String stringValue) {
int charLength = stringValue.length();
if (charLength > 65535) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException("Maximum size for a UTF-8 string constant exceeded");
}
int currentLength = length;
if (currentLength + 2 + charLength > data.length) {
diff --git a/asm/src/main/java/org/objectweb/asm/ClassTooLargeException.java b/asm/src/main/java/org/objectweb/asm/ClassTooLargeException.java
new file mode 100644
index 00000000..a206e695
--- /dev/null
+++ b/asm/src/main/java/org/objectweb/asm/ClassTooLargeException.java
@@ -0,0 +1,53 @@
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+package org.objectweb.asm;
+
+public final class ClassTooLargeException extends IndexOutOfBoundsException {
+ private final String className;
+ private final int constantPoolCount;
+
+ /**
+ * @return The name of the class, or null if not known
+ */
+ public String getClassName() {
+ return className;
+ }
+
+ /**
+ * @return The number of byte codes in the method.
+ */
+ public int getConstantPoolCount() {
+ return constantPoolCount;
+ }
+
+ public ClassTooLargeException(String className, int constantPoolCount) {
+ super("Class file too large" + (className == null ? "" : ": " + className));
+ this.className = className;
+ this.constantPoolCount = constantPoolCount;
+ }
+}
diff --git a/asm/src/main/java/org/objectweb/asm/ClassWriter.java b/asm/src/main/java/org/objectweb/asm/ClassWriter.java
index 5005c8b0..ac064ce5 100644
--- a/asm/src/main/java/org/objectweb/asm/ClassWriter.java
+++ b/asm/src/main/java/org/objectweb/asm/ClassWriter.java
@@ -543,8 +543,9 @@ public byte[] toByteArray() {
// IMPORTANT: this must be the last part of the ClassFile size computation, because the previous
// statements can add attribute names to the constant pool, thereby changing its size!
size += symbolTable.getConstantPoolLength();
- if (symbolTable.getConstantPoolCount() > 0xFFFF) {
- throw new IndexOutOfBoundsException("Class file too large!");
+ int constantPoolCount = symbolTable.getConstantPoolCount();
+ if (constantPoolCount > 0xFFFF) {
+ throw new ClassTooLargeException(symbolTable.getClassName(), constantPoolCount);
}
// Second step: allocate a ByteVector of the correct size (in order to avoid any array copy in
diff --git a/asm/src/main/java/org/objectweb/asm/MethodTooLargeException.java b/asm/src/main/java/org/objectweb/asm/MethodTooLargeException.java
new file mode 100644
index 00000000..9e106e93
--- /dev/null
+++ b/asm/src/main/java/org/objectweb/asm/MethodTooLargeException.java
@@ -0,0 +1,71 @@
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
+package org.objectweb.asm;
+
+public final class MethodTooLargeException extends IndexOutOfBoundsException {
+ private final String className;
+ private final String methodName;
+ private final String descriptor;
+ private final int codeSize;
+
+ /**
+ * @return The name of the enclosing class, or null if not known
+ */
+ public String getClassName() {
+ return className;
+ }
+
+ /**
+ * @return The name of the method
+ */
+ public String getMethodName() {
+ return methodName;
+ }
+
+ /**
+ * @return The descriptor of the the method
+ */
+ public String getDescriptor() {
+ return descriptor;
+ }
+
+ /**
+ * @return The number of byte codes in the method.
+ */
+ public int getCodeSize() {
+ return codeSize;
+ }
+
+ public MethodTooLargeException(String className, String methodName, String descriptor, int codeSize) {
+ super("Method code too large: " + (className == null ? "" : className + ".") + methodName + " " + descriptor);
+ this.className = className;
+ this.methodName = methodName;
+ this.descriptor = descriptor;
+ this.codeSize = codeSize;
+ }
+}
diff --git a/asm/src/main/java/org/objectweb/asm/MethodWriter.java b/asm/src/main/java/org/objectweb/asm/MethodWriter.java
index b49f986a..8b35e9bd 100644
--- a/asm/src/main/java/org/objectweb/asm/MethodWriter.java
+++ b/asm/src/main/java/org/objectweb/asm/MethodWriter.java
@@ -305,6 +305,9 @@ final class MethodWriter extends MethodVisitor {
/** The descriptor of this method. */
private final String descriptor;
+ /** The name of this method. */
+ private final String name;
+
// Code attribute fields and sub attributes:
/** The max_stack field of the Code attribute. */
@@ -592,6 +595,7 @@ final class MethodWriter extends MethodVisitor {
this.symbolTable = symbolTable;
this.accessFlags = "".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access;
this.nameIndex = symbolTable.addConstantUtf8(name);
+ this.name = name;
this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
this.descriptor = descriptor;
this.signatureIndex = signature == null ? 0 : symbolTable.addConstantUtf8(signature);
@@ -2058,7 +2062,7 @@ int computeMethodInfoSize() {
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
if (code.length > 0) {
if (code.length > 65535) {
- throw new IndexOutOfBoundsException("Method code too large!");
+ throw new MethodTooLargeException(symbolTable.getClassName(), name, descriptor, code.length);
}
symbolTable.addConstantUtf8(Constants.CODE);
// The Code attribute has 6 header bytes, plus 2, 2, 4 and 2 bytes respectively for max_stack,
diff --git a/asm/src/test/java/org/objectweb/asm/ByteVectorTest.java b/asm/src/test/java/org/objectweb/asm/ByteVectorTest.java
index 75042e77..00db4640 100644
--- a/asm/src/test/java/org/objectweb/asm/ByteVectorTest.java
+++ b/asm/src/test/java/org/objectweb/asm/ByteVectorTest.java
@@ -32,6 +32,10 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.Arrays;
/**
* ByteVector tests.
@@ -113,12 +117,25 @@ public void testPutUTF8_unicode() {
assertContains(byteVector, 0, 8, 'a', -64, -128, -62, -128, -32, -96, -128);
char[] charBuffer = new char[32768];
- for (int i = 0; i < charBuffer.length; ++i) {
- charBuffer[i] = '\u07FF';
- }
+ Arrays.fill(charBuffer, '\u07FF');
assertThrows(IllegalArgumentException.class, () -> byteVector.putUTF8(new String(charBuffer)));
}
+ @ParameterizedTest
+ @ValueSource(ints = {65535, 65536})
+ public void testPutUTF8_tooLong(int size) {
+ ByteVector byteVector = new ByteVector(0);
+ char[] charBuffer = new char[size];
+ Arrays.fill(charBuffer, 'A');
+ String s = new String(charBuffer);
+ if (size > 65535) {
+ IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> byteVector.putUTF8(s));
+ assertEquals("Maximum size for a UTF-8 string constant exceeded", thrown.getMessage());
+ } else {
+ byteVector.putUTF8(s);
+ }
+ }
+
@Test
public void testPutByteArray() {
ByteVector byteVector = new ByteVector(0);
diff --git a/asm/src/test/java/org/objectweb/asm/ClassWriterTest.java b/asm/src/test/java/org/objectweb/asm/ClassWriterTest.java
index 67595b62..15c1a051 100644
--- a/asm/src/test/java/org/objectweb/asm/ClassWriterTest.java
+++ b/asm/src/test/java/org/objectweb/asm/ClassWriterTest.java
@@ -28,8 +28,7 @@
package org.objectweb.asm;
import static java.util.stream.Collectors.toSet;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.*;
import static org.objectweb.asm.test.Assertions.assertThat;
import java.io.FileInputStream;
@@ -129,11 +128,18 @@ public void testNewConst() {
@ValueSource(ints = {65535, 65536})
public void testConstantPoolSizeTooLarge(final int constantPoolCount) {
ClassWriter classWriter = new ClassWriter(0);
- for (int i = 0; i < constantPoolCount - 1; ++i) {
+ String className = "A";
+ classWriter.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", null);
+ int initConstantPoolCount = 5;
+ // assert(initConstantPoolCount == classWriter.symbolTable.getConstantPoolCount())
+ for (int i = 0; i < constantPoolCount - initConstantPoolCount; ++i) {
classWriter.newConst(Integer.valueOf(i));
}
if (constantPoolCount > 65535) {
- assertThrows(IndexOutOfBoundsException.class, () -> classWriter.toByteArray());
+ ClassTooLargeException thrown = assertThrows(ClassTooLargeException.class, () -> classWriter.toByteArray());
+ assertEquals(className, thrown.getClassName());
+ assertEquals(constantPoolCount, thrown.getConstantPoolCount());
+ assertEquals("Class file too large: A", thrown.getMessage());
} else {
classWriter.toByteArray();
}
@@ -143,8 +149,10 @@ public void testConstantPoolSizeTooLarge(final int constantPoolCount) {
@ValueSource(ints = {65535, 65536})
void testMethodCodeSizeTooLarge(final int methodCodeSize) {
ClassWriter classWriter = new ClassWriter(0);
+ String methodName = "m";
+ String descriptor = "()V";
MethodVisitor methodVisitor =
- classWriter.visitMethod(Opcodes.ACC_STATIC, "m", "()V", null, null);
+ classWriter.visitMethod(Opcodes.ACC_STATIC, methodName, descriptor, null, null);
methodVisitor.visitCode();
for (int i = 0; i < methodCodeSize - 1; ++i) {
methodVisitor.visitInsn(Opcodes.NOP);
@@ -153,7 +161,12 @@ void testMethodCodeSizeTooLarge(final int methodCodeSize) {
methodVisitor.visitMaxs(0, 0);
methodVisitor.visitEnd();
if (methodCodeSize > 65535) {
- assertThrows(IndexOutOfBoundsException.class, () -> classWriter.toByteArray());
+ MethodTooLargeException thrown = assertThrows(MethodTooLargeException.class, () -> classWriter.toByteArray());
+ assertEquals(methodName, thrown.getMethodName());
+ assertNull(thrown.getClassName());
+ assertEquals(descriptor, thrown.getDescriptor());
+ assertEquals(methodCodeSize, thrown.getCodeSize());
+ assertEquals("Method code too large: m ()V", thrown.getMessage());
} else {
classWriter.toByteArray();
}