Commit d209ecc3 authored by Eric Bruneton's avatar Eric Bruneton

Merge branch 'retronymm/asm-unfork/error-messages'

parents 416c88f6 94a06049
......@@ -242,7 +242,7 @@ public class ByteVector {
public ByteVector putUTF8(final String stringValue) {
int charLength = stringValue.length();
if (charLength > 65535) {
throw new IllegalArgumentException();
throw new IllegalArgumentException("UTF8 string too large");
}
int currentLength = length;
if (currentLength + 2 + charLength > data.length) {
......@@ -294,7 +294,7 @@ public class ByteVector {
}
}
if (byteLength > maxByteLength) {
throw new IllegalArgumentException();
throw new IllegalArgumentException("UTF8 string too large");
}
// Compute where 'byteLength' must be stored in 'data', and store it at this location.
int byteLengthOffset = length - offset - 2;
......
// 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;
/**
* Exception thrown when the constant pool of a class produced by a {@link ClassWriter} is too
* large.
*
* @author Jason Zaugg
*/
public final class ClassTooLargeException extends IndexOutOfBoundsException {
private final String className;
private final int constantPoolCount;
/**
* Constructs a new {@link ClassTooLargeException}.
*
* @param className the internal name of the class.
* @param constantPoolCount the number of constant pool items of the class.
*/
public ClassTooLargeException(final String className, final int constantPoolCount) {
super("Class too large: " + className);
this.className = className;
this.constantPoolCount = constantPoolCount;
}
/** @return the internal name of the class. */
public String getClassName() {
return className;
}
/** @return the number of constant pool items of the class. */
public int getConstantPoolCount() {
return constantPoolCount;
}
}
......@@ -436,8 +436,10 @@ public class ClassWriter extends ClassVisitor {
* Returns the content of the class file that was built by this ClassWriter.
*
* @return the binary content of the JVMS ClassFile structure that was built by this ClassWriter.
* @throws ClassTooLargeException if the constant pool of the class is too large.
* @throws MethodTooLargeException if the Code attribute of a method is too large.
*/
public byte[] toByteArray() {
public byte[] toByteArray() throws ClassTooLargeException, MethodTooLargeException {
// First step: compute the size in bytes of the ClassFile structure.
// The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version,
// constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count,
......@@ -543,8 +545,9 @@ public class ClassWriter extends ClassVisitor {
// 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
......
// 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;
/**
* Exception thrown when the Code attribute of a method produced by a {@link ClassWriter} is too
* large.
*
* @author Jason Zaugg
*/
public final class MethodTooLargeException extends IndexOutOfBoundsException {
private final String className;
private final String methodName;
private final String descriptor;
private final int codeSize;
/**
* Constructs a new {@link MethodTooLargeException}.
*
* @param className the internal name of the owner class.
* @param methodName the name of the method.
* @param descriptor the descriptor of the method.
* @param codeSize the size of the method's Code attribute, in bytes.
*/
public MethodTooLargeException(
final String className,
final String methodName,
final String descriptor,
final int codeSize) {
super("Method too large: " + className + "." + methodName + " " + descriptor);
this.className = className;
this.methodName = methodName;
this.descriptor = descriptor;
this.codeSize = codeSize;
}
/** @return the internal name of the owner class. */
public String getClassName() {
return className;
}
/** @return the name of the method. */
public String getMethodName() {
return methodName;
}
/** @return the descriptor of the method. */
public String getDescriptor() {
return descriptor;
}
/** @return the size of the method's Code attribute, in bytes. */
public int getCodeSize() {
return codeSize;
}
}
......@@ -299,6 +299,9 @@ final class MethodWriter extends MethodVisitor {
/** The name_index field of the method_info JVMS structure. */
private final int nameIndex;
/** The name of this method. */
private final String name;
/** The descriptor_index field of the method_info JVMS structure. */
private final int descriptorIndex;
......@@ -592,6 +595,7 @@ final class MethodWriter extends MethodVisitor {
this.symbolTable = symbolTable;
this.accessFlags = "<init>".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,8 @@ final class MethodWriter extends MethodVisitor {
// 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,
......
......@@ -31,7 +31,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
/**
* ByteVector tests.
......@@ -113,10 +116,27 @@ public class ByteVectorTest {
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');
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class, () -> byteVector.putUTF8(new String(charBuffer)));
assertEquals("UTF8 string too large", thrown.getMessage());
}
@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 utf8 = new String(charBuffer);
if (size > 65535) {
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> byteVector.putUTF8(utf8));
assertEquals("UTF8 string too large", thrown.getMessage());
} else {
byteVector.putUTF8(utf8);
}
assertThrows(IllegalArgumentException.class, () -> byteVector.putUTF8(new String(charBuffer)));
}
@Test
......
......@@ -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 class ClassWriterTest extends AsmTest {
@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;
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 too large: A", thrown.getMessage());
} else {
classWriter.toByteArray();
}
......@@ -143,8 +149,12 @@ public class ClassWriterTest extends AsmTest {
@ValueSource(ints = {65535, 65536})
void testMethodCodeSizeTooLarge(final int methodCodeSize) {
ClassWriter classWriter = new ClassWriter(0);
String className = "A";
String methodName = "m";
String descriptor = "()V";
classWriter.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", null);
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 +163,13 @@ public class ClassWriterTest extends AsmTest {
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());
assertEquals(className, thrown.getClassName());
assertEquals(descriptor, thrown.getDescriptor());
assertEquals(methodCodeSize, thrown.getCodeSize());
assertEquals("Method too large: A.m ()V", thrown.getMessage());
} else {
classWriter.toByteArray();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment