8302514: Misleading error generated when empty class file encountered
Reviewed-by: vromero, jwaters
This commit is contained in:
parent
3cc459b6c2
commit
a58fa6e73e
@ -62,6 +62,7 @@ import com.sun.tools.javac.main.Option;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Warnings;
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.util.ByteBuffer.UnderflowException;
|
||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
|
||||
@ -329,7 +330,12 @@ public class ClassReader {
|
||||
/** Read a character.
|
||||
*/
|
||||
char nextChar() {
|
||||
char res = buf.getChar(bp);
|
||||
char res;
|
||||
try {
|
||||
res = buf.getChar(bp);
|
||||
} catch (UnderflowException e) {
|
||||
throw badClassFile("bad.class.truncated.at.offset", Integer.toString(e.getLength()));
|
||||
}
|
||||
bp += 2;
|
||||
return res;
|
||||
}
|
||||
@ -337,13 +343,22 @@ public class ClassReader {
|
||||
/** Read a byte.
|
||||
*/
|
||||
int nextByte() {
|
||||
return buf.getByte(bp++) & 0xFF;
|
||||
try {
|
||||
return buf.getByte(bp++) & 0xFF;
|
||||
} catch (UnderflowException e) {
|
||||
throw badClassFile("bad.class.truncated.at.offset", Integer.toString(e.getLength()));
|
||||
}
|
||||
}
|
||||
|
||||
/** Read an integer.
|
||||
*/
|
||||
int nextInt() {
|
||||
int res = buf.getInt(bp);
|
||||
int res;
|
||||
try {
|
||||
res = buf.getInt(bp);
|
||||
} catch (UnderflowException e) {
|
||||
throw badClassFile("bad.class.truncated.at.offset", Integer.toString(e.getLength()));
|
||||
}
|
||||
bp += 4;
|
||||
return res;
|
||||
}
|
||||
@ -1482,7 +1497,12 @@ public class ClassReader {
|
||||
/** Read parameter annotations.
|
||||
*/
|
||||
void readParameterAnnotations(Symbol meth) {
|
||||
int numParameters = buf.getByte(bp++) & 0xFF;
|
||||
int numParameters;
|
||||
try {
|
||||
numParameters = buf.getByte(bp++) & 0xFF;
|
||||
} catch (UnderflowException e) {
|
||||
throw badClassFile("bad.class.truncated.at.offset", Integer.toString(e.getLength()));
|
||||
}
|
||||
if (parameterAnnotations == null) {
|
||||
parameterAnnotations = new ParameterAnnotations[numParameters];
|
||||
} else if (parameterAnnotations.length != numParameters) {
|
||||
@ -1771,7 +1791,12 @@ public class ClassReader {
|
||||
}
|
||||
|
||||
Attribute readAttributeValue() {
|
||||
char c = (char) buf.getByte(bp++);
|
||||
char c;
|
||||
try {
|
||||
c = (char)buf.getByte(bp++);
|
||||
} catch (UnderflowException e) {
|
||||
throw badClassFile("bad.class.truncated.at.offset", Integer.toString(e.getLength()));
|
||||
}
|
||||
switch (c) {
|
||||
case 'B':
|
||||
return new Attribute.Constant(syms.byteType, poolReader.getConstant(nextChar()));
|
||||
|
@ -25,6 +25,7 @@
|
||||
package com.sun.tools.javac.jvm;
|
||||
|
||||
import com.sun.tools.javac.util.ByteBuffer;
|
||||
import com.sun.tools.javac.util.ByteBuffer.UnderflowException;
|
||||
import com.sun.tools.javac.util.Convert;
|
||||
import com.sun.tools.javac.util.Name.NameMapper;
|
||||
|
||||
@ -132,16 +133,26 @@ public class ModuleNameReader {
|
||||
|
||||
/** Read a character.
|
||||
*/
|
||||
char nextChar() {
|
||||
char res = buf.getChar(bp);
|
||||
char nextChar() throws BadClassFile {
|
||||
char res;
|
||||
try {
|
||||
res = buf.getChar(bp);
|
||||
} catch (UnderflowException e) {
|
||||
throw new BadClassFile("class file truncated at offset " + e.getLength());
|
||||
}
|
||||
bp += 2;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Read an integer.
|
||||
*/
|
||||
int nextInt() {
|
||||
int res = buf.getInt(bp);
|
||||
int nextInt() throws BadClassFile {
|
||||
int res;
|
||||
try {
|
||||
res = buf.getInt(bp);
|
||||
} catch (UnderflowException e) {
|
||||
throw new BadClassFile("class file truncated at offset " + e.getLength());
|
||||
}
|
||||
bp += 4;
|
||||
return res;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.jvm.PoolConstant.NameAndType;
|
||||
import com.sun.tools.javac.util.ByteBuffer;
|
||||
import com.sun.tools.javac.util.ByteBuffer.UnderflowException;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
import com.sun.tools.javac.util.Name.NameMapper;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
@ -118,21 +119,30 @@ public class PoolReader {
|
||||
* Get class name without resolving
|
||||
*/
|
||||
<Z> Z peekClassName(int index, NameMapper<Z> mapper) {
|
||||
return peekName(buf.getChar(pool.offset(index)), mapper);
|
||||
return peekItemName(index, mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get package name without resolving
|
||||
*/
|
||||
<Z> Z peekPackageName(int index, NameMapper<Z> mapper) {
|
||||
return peekName(buf.getChar(pool.offset(index)), mapper);
|
||||
return peekItemName(index, mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get module name without resolving
|
||||
*/
|
||||
<Z> Z peekModuleName(int index, NameMapper<Z> mapper) {
|
||||
return peekName(buf.getChar(pool.offset(index)), mapper);
|
||||
return peekItemName(index, mapper);
|
||||
}
|
||||
|
||||
private <Z> Z peekItemName(int index, NameMapper<Z> mapper) {
|
||||
try {
|
||||
index = buf.getChar(pool.offset(index));
|
||||
} catch (UnderflowException e) {
|
||||
throw reader.badClassFile("bad.class.truncated.at.offset", Integer.toString(e.getLength()));
|
||||
}
|
||||
return peekName(index, mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,7 +163,11 @@ public class PoolReader {
|
||||
* Peek a name from the pool at given index without resolving.
|
||||
*/
|
||||
<Z> Z peekName(int index, Name.NameMapper<Z> mapper) {
|
||||
return getUtf8(index, mapper);
|
||||
try {
|
||||
return getUtf8(index, mapper);
|
||||
} catch (UnderflowException e) {
|
||||
throw reader.badClassFile("bad.class.truncated.at.offset", Integer.toString(e.getLength()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,7 +202,7 @@ public class PoolReader {
|
||||
return pool.tag(index) == tag;
|
||||
}
|
||||
|
||||
private <Z> Z getUtf8(int index, NameMapper<Z> mapper) {
|
||||
private <Z> Z getUtf8(int index, NameMapper<Z> mapper) throws UnderflowException {
|
||||
int tag = pool.tag(index);
|
||||
int offset = pool.offset(index);
|
||||
if (tag == CONSTANT_Utf8) {
|
||||
@ -201,7 +215,7 @@ public class PoolReader {
|
||||
}
|
||||
}
|
||||
|
||||
private Object resolve(ByteBuffer poolbuf, int tag, int offset) {
|
||||
private Object resolve(ByteBuffer poolbuf, int tag, int offset) throws UnderflowException {
|
||||
switch (tag) {
|
||||
case CONSTANT_Utf8: {
|
||||
int len = poolbuf.getChar(offset);
|
||||
@ -250,6 +264,14 @@ public class PoolReader {
|
||||
* {@link PoolReader#peekClassName(int, NameMapper)}.
|
||||
*/
|
||||
int readPool(ByteBuffer poolbuf, int offset) {
|
||||
try {
|
||||
return readPoolInternal(poolbuf, offset);
|
||||
} catch (UnderflowException e) {
|
||||
throw reader.badClassFile("bad.class.truncated.at.offset", Integer.toString(e.getLength()));
|
||||
}
|
||||
}
|
||||
|
||||
private int readPoolInternal(ByteBuffer poolbuf, int offset) throws UnderflowException {
|
||||
int poolSize = poolbuf.getChar(offset);
|
||||
int index = 1;
|
||||
offset += 2;
|
||||
@ -343,7 +365,12 @@ public class PoolReader {
|
||||
if (!expectedTags.get(currentTag)) {
|
||||
throw reader.badClassFile("unexpected.const.pool.tag.at", tag(index), offset(index));
|
||||
}
|
||||
P p = (P)resolve(poolbuf, tag(index), offset(index));
|
||||
P p;
|
||||
try {
|
||||
p = (P)resolve(poolbuf, tag(index), offset(index));
|
||||
} catch (UnderflowException e) {
|
||||
throw reader.badClassFile("bad.class.truncated.at.offset", Integer.toString(e.getLength()));
|
||||
}
|
||||
values[index] = p;
|
||||
return p;
|
||||
}
|
||||
|
@ -2431,6 +2431,9 @@ compiler.misc.bad.const.pool.tag.at=\
|
||||
compiler.misc.unexpected.const.pool.tag.at=\
|
||||
unexpected constant pool tag: {0} at {1}
|
||||
|
||||
compiler.misc.bad.class.truncated.at.offset=\
|
||||
class file truncated at offset {0}
|
||||
|
||||
compiler.misc.bad.signature=\
|
||||
bad signature: {0}
|
||||
|
||||
|
@ -35,12 +35,30 @@ import java.lang.reflect.Array;
|
||||
public class ArrayUtils {
|
||||
|
||||
private static int calculateNewLength(int currentLength, int maxIndex) {
|
||||
while (currentLength < maxIndex + 1)
|
||||
if (maxIndex == Integer.MAX_VALUE)
|
||||
maxIndex--; // avoid negative overflow
|
||||
while (currentLength < maxIndex + 1) {
|
||||
currentLength = currentLength * 2;
|
||||
if (currentLength <= 0) { // avoid infinite loop and negative overflow
|
||||
currentLength = maxIndex + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return currentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the given array has length at least {@code maxIndex + 1}.
|
||||
*
|
||||
* @param array original array
|
||||
* @param maxIndex exclusive lower bound for desired length
|
||||
* @return possibly reallocated array of length at least {@code maxIndex + 1}
|
||||
* @throws NullPointerException if {@code array} is null
|
||||
* @throws IllegalArgumentException if {@code maxIndex} is negative
|
||||
*/
|
||||
public static <T> T[] ensureCapacity(T[] array, int maxIndex) {
|
||||
if (maxIndex < 0)
|
||||
throw new IllegalArgumentException("maxIndex=" + maxIndex);
|
||||
if (maxIndex < array.length) {
|
||||
return array;
|
||||
} else {
|
||||
@ -52,7 +70,18 @@ public class ArrayUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the given array has length at least {@code maxIndex + 1}.
|
||||
*
|
||||
* @param array original array
|
||||
* @param maxIndex exclusive lower bound for desired length
|
||||
* @return possibly reallocated array of length at least {@code maxIndex + 1}
|
||||
* @throws NullPointerException if {@code array} is null
|
||||
* @throws IllegalArgumentException if {@code maxIndex} is negative
|
||||
*/
|
||||
public static byte[] ensureCapacity(byte[] array, int maxIndex) {
|
||||
if (maxIndex < 0)
|
||||
throw new IllegalArgumentException("maxIndex=" + maxIndex);
|
||||
if (maxIndex < array.length) {
|
||||
return array;
|
||||
} else {
|
||||
@ -63,7 +92,18 @@ public class ArrayUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the given array has length at least {@code maxIndex + 1}.
|
||||
*
|
||||
* @param array original array
|
||||
* @param maxIndex exclusive lower bound for desired length
|
||||
* @return possibly reallocated array of length at least {@code maxIndex + 1}
|
||||
* @throws NullPointerException if {@code array} is null
|
||||
* @throws IllegalArgumentException if {@code maxIndex} is negative
|
||||
*/
|
||||
public static char[] ensureCapacity(char[] array, int maxIndex) {
|
||||
if (maxIndex < 0)
|
||||
throw new IllegalArgumentException("maxIndex=" + maxIndex);
|
||||
if (maxIndex < array.length) {
|
||||
return array;
|
||||
} else {
|
||||
@ -74,7 +114,18 @@ public class ArrayUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the given array has length at least {@code maxIndex + 1}.
|
||||
*
|
||||
* @param array original array
|
||||
* @param maxIndex exclusive lower bound for desired length
|
||||
* @return possibly reallocated array of length at least {@code maxIndex + 1}
|
||||
* @throws NullPointerException if {@code array} is null
|
||||
* @throws IllegalArgumentException if {@code maxIndex} is negative
|
||||
*/
|
||||
public static int[] ensureCapacity(int[] array, int maxIndex) {
|
||||
if (maxIndex < 0)
|
||||
throw new IllegalArgumentException("maxIndex=" + maxIndex);
|
||||
if (maxIndex < array.length) {
|
||||
return array;
|
||||
} else {
|
||||
|
@ -147,35 +147,42 @@ public class ByteBuffer {
|
||||
appendBytes(name.getByteArray(), name.getByteOffset(), name.getByteLength());
|
||||
}
|
||||
|
||||
/** Append the content of a given input stream.
|
||||
/** Append the content of a given input stream, and then close the stream.
|
||||
*/
|
||||
public void appendStream(InputStream is) throws IOException {
|
||||
try {
|
||||
int start = length;
|
||||
int initialSize = is.available();
|
||||
elems = ArrayUtils.ensureCapacity(elems, length + initialSize);
|
||||
int r = is.read(elems, start, initialSize);
|
||||
int bp = start;
|
||||
while (r != -1) {
|
||||
bp += r;
|
||||
elems = ArrayUtils.ensureCapacity(elems, bp);
|
||||
r = is.read(elems, bp, elems.length - bp);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
/* Ignore any errors, as this stream may have already
|
||||
* thrown a related exception which is the one that
|
||||
* should be reported.
|
||||
*/
|
||||
try (InputStream input = is) {
|
||||
while (true) {
|
||||
|
||||
// Read another chunk of data, using size hint from available().
|
||||
// If available() is accurate, the array size should be just right.
|
||||
int amountToRead = Math.max(input.available(), 64);
|
||||
elems = ArrayUtils.ensureCapacity(elems, length + amountToRead);
|
||||
int amountRead = input.read(elems, length, amountToRead);
|
||||
if (amountRead == -1)
|
||||
break;
|
||||
length += amountRead;
|
||||
|
||||
// Check for the common case where input.available() returned the
|
||||
// entire remaining input; in that case, avoid an extra array extension.
|
||||
// Note we are guaranteed that elems.length >= length + 1 at this point.
|
||||
if (amountRead == amountToRead) {
|
||||
int byt = input.read();
|
||||
if (byt == -1)
|
||||
break;
|
||||
elems[length++] = (byte)byt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Extract an integer at position bp from elems.
|
||||
*
|
||||
* @param bp starting offset
|
||||
* @throws UnderflowException if there is not enough data in this buffer
|
||||
* @throws IllegalArgumentException if {@code bp} is negative
|
||||
*/
|
||||
public int getInt(int bp) {
|
||||
public int getInt(int bp) throws UnderflowException {
|
||||
verifyRange(bp, 4);
|
||||
return
|
||||
((elems[bp] & 0xFF) << 24) +
|
||||
((elems[bp+1] & 0xFF) << 16) +
|
||||
@ -185,8 +192,13 @@ public class ByteBuffer {
|
||||
|
||||
|
||||
/** Extract a long integer at position bp from elems.
|
||||
*
|
||||
* @param bp starting offset
|
||||
* @throws UnderflowException if there is not enough data in this buffer
|
||||
* @throws IllegalArgumentException if {@code bp} is negative
|
||||
*/
|
||||
public long getLong(int bp) {
|
||||
public long getLong(int bp) throws UnderflowException {
|
||||
verifyRange(bp, 8);
|
||||
DataInputStream elemsin =
|
||||
new DataInputStream(new ByteArrayInputStream(elems, bp, 8));
|
||||
try {
|
||||
@ -197,8 +209,13 @@ public class ByteBuffer {
|
||||
}
|
||||
|
||||
/** Extract a float at position bp from elems.
|
||||
*
|
||||
* @param bp starting offset
|
||||
* @throws UnderflowException if there is not enough data in this buffer
|
||||
* @throws IllegalArgumentException if {@code bp} is negative
|
||||
*/
|
||||
public float getFloat(int bp) {
|
||||
public float getFloat(int bp) throws UnderflowException {
|
||||
verifyRange(bp, 4);
|
||||
DataInputStream elemsin =
|
||||
new DataInputStream(new ByteArrayInputStream(elems, bp, 4));
|
||||
try {
|
||||
@ -209,8 +226,13 @@ public class ByteBuffer {
|
||||
}
|
||||
|
||||
/** Extract a double at position bp from elems.
|
||||
*
|
||||
* @param bp starting offset
|
||||
* @throws UnderflowException if there is not enough data in this buffer
|
||||
* @throws IllegalArgumentException if {@code bp} is negative
|
||||
*/
|
||||
public double getDouble(int bp) {
|
||||
public double getDouble(int bp) throws UnderflowException {
|
||||
verifyRange(bp, 8);
|
||||
DataInputStream elemsin =
|
||||
new DataInputStream(new ByteArrayInputStream(elems, bp, 8));
|
||||
try {
|
||||
@ -221,13 +243,25 @@ public class ByteBuffer {
|
||||
}
|
||||
|
||||
/** Extract a character at position bp from elems.
|
||||
*
|
||||
* @param bp starting offset
|
||||
* @throws UnderflowException if there is not enough data in this buffer
|
||||
* @throws IllegalArgumentException if {@code bp} is negative
|
||||
*/
|
||||
public char getChar(int bp) {
|
||||
public char getChar(int bp) throws UnderflowException {
|
||||
verifyRange(bp, 2);
|
||||
return
|
||||
(char)(((elems[bp] & 0xFF) << 8) + (elems[bp+1] & 0xFF));
|
||||
}
|
||||
|
||||
public byte getByte(int bp) {
|
||||
/** Extract a byte at position bp from elems.
|
||||
*
|
||||
* @param bp starting offset
|
||||
* @throws UnderflowException if there is not enough data in this buffer
|
||||
* @throws IllegalArgumentException if {@code bp} is negative
|
||||
*/
|
||||
public byte getByte(int bp) throws UnderflowException {
|
||||
verifyRange(bp, 1);
|
||||
return elems[bp];
|
||||
}
|
||||
|
||||
@ -242,4 +276,39 @@ public class ByteBuffer {
|
||||
public Name toName(Names names) {
|
||||
return names.fromUtf(elems, 0, length);
|
||||
}
|
||||
|
||||
/** Verify there are at least the specified number of bytes in this buffer at the specified offset.
|
||||
*
|
||||
* @param off starting offset
|
||||
* @param len required length
|
||||
* @throws UnderflowException if there is not enough data in this buffer
|
||||
* @throws IllegalArgumentException if {@code off} or {@code len} is negative
|
||||
*/
|
||||
public void verifyRange(int off, int len) throws UnderflowException {
|
||||
if (off < 0 || len < 0)
|
||||
throw new IllegalArgumentException("off=" + off + ", len=" + len);
|
||||
if (off + len < 0 || off + len > length)
|
||||
throw new UnderflowException(length);
|
||||
}
|
||||
|
||||
// UnderflowException
|
||||
|
||||
/** Thrown when trying to read past the end of the buffer.
|
||||
*/
|
||||
public static class UnderflowException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
|
||||
private final int length;
|
||||
|
||||
public UnderflowException(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
/** Get the length of the buffer, which apparently is not long enough.
|
||||
*/
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8302514
|
||||
* @summary Verify truncated class files are detected and reported as truncated
|
||||
*/
|
||||
|
||||
import com.sun.tools.javac.Main;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class TruncatedClassFileTest {
|
||||
|
||||
// We want a bunch of stuff in this file to make the classfile complicated
|
||||
private static final String A_SOURCE = """
|
||||
public class ClassA {
|
||||
public static final boolean z = true;
|
||||
public static final byte b = 7;
|
||||
public static final char c = '*';
|
||||
public static final short s = -12;
|
||||
public static final int i = 123;
|
||||
public static final float f = 123f;
|
||||
public static final long j = 0x1234567812345678L;
|
||||
public static final double d = Math.PI;
|
||||
public static final String str = new String("test123");
|
||||
@SuppressWarnings("blah")
|
||||
public ClassA() {
|
||||
new Thread();
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
// This file will get compiled against a trunctated version of A.class
|
||||
private static final String B_SOURCE = """
|
||||
public class ClassB {
|
||||
public ClassB() {
|
||||
new ClassA();
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
private static final File A_SOURCE_FILE = new File("ClassA.java");
|
||||
private static final File B_SOURCE_FILE = new File("ClassB.java");
|
||||
private static final File A_CLASS_FILE = new File("ClassA.class");
|
||||
|
||||
private static void createSourceFile(File file, String content) throws IOException {
|
||||
try (PrintStream output = new PrintStream(new FileOutputStream(file))) {
|
||||
output.println(content);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
|
||||
// Create A.java and B.java
|
||||
createSourceFile(A_SOURCE_FILE, A_SOURCE);
|
||||
createSourceFile(B_SOURCE_FILE, B_SOURCE);
|
||||
|
||||
// Compile A.java
|
||||
createSourceFile(A_SOURCE_FILE, A_SOURCE);
|
||||
int ret = Main.compile(new String[] { A_SOURCE_FILE.toString() });
|
||||
if (ret != 0)
|
||||
throw new AssertionError("compilation of " + A_SOURCE_FILE + " failed");
|
||||
A_SOURCE_FILE.delete();
|
||||
|
||||
// Read A.class
|
||||
final byte[] classfile = Files.readAllBytes(A_CLASS_FILE.toPath());
|
||||
|
||||
// Now compile B.java with truncated versions of A.class
|
||||
for (int length = 0; length < classfile.length; length++) {
|
||||
|
||||
// Write out truncated class file A.class
|
||||
try (FileOutputStream output = new FileOutputStream(A_CLASS_FILE)) {
|
||||
output.write(classfile, 0, length);
|
||||
}
|
||||
|
||||
// Try to compile file B.java
|
||||
final StringWriter diags = new StringWriter();
|
||||
final String[] params = new String[] {
|
||||
"-classpath",
|
||||
".",
|
||||
"-XDrawDiagnostics",
|
||||
B_SOURCE_FILE.toString()
|
||||
};
|
||||
ret = Main.compile(params, new PrintWriter(diags, true));
|
||||
if (ret == 0)
|
||||
throw new AssertionError("compilation with truncated class file (" + length + ") succeeded?");
|
||||
final String errmsg = "compiler.misc.bad.class.truncated.at.offset: " + length;
|
||||
if (!diags.toString().contains(errmsg))
|
||||
throw new AssertionError("error message not found for truncated class file (" + length + "): " + diags);
|
||||
}
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@ compiler.err.type.var.more.than.once # UNUSED
|
||||
compiler.err.type.var.more.than.once.in.result # UNUSED
|
||||
compiler.err.unexpected.type
|
||||
compiler.misc.bad.class.signature # bad class file
|
||||
compiler.misc.bad.class.truncated.at.offset # bad class file
|
||||
compiler.misc.bad.const.pool.tag # bad class file
|
||||
compiler.misc.bad.const.pool.tag.at # bad class file
|
||||
compiler.misc.unexpected.const.pool.tag.at # bad class file
|
||||
|
@ -381,7 +381,7 @@ public class EdgeCases extends ModuleTestBase {
|
||||
.getOutputLines(OutputKind.DIRECT);
|
||||
|
||||
List<String> expected = Arrays.asList(
|
||||
"- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.illegal.start.of.class.file))",
|
||||
"- compiler.err.cant.access: <error>.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.bad.class.truncated.at.offset: 0))",
|
||||
"1 error");
|
||||
|
||||
if (!expected.equals(log)) {
|
||||
|
@ -102,7 +102,7 @@ public class NoAbortForBadClassFile extends TestRunner {
|
||||
.getOutputLines(Task.OutputKind.DIRECT);
|
||||
|
||||
List<String> expectedOut = Arrays.asList(
|
||||
"Test.java:1:57: compiler.err.cant.access: test.Broken, (compiler.misc.bad.class.file.header: Broken.class, (compiler.misc.class.file.wrong.class: java.lang.AutoCloseable))",
|
||||
"Test.java:1:57: compiler.err.cant.access: test.Broken, (compiler.misc.bad.class.file.header: Broken.class, (compiler.misc.bad.class.truncated.at.offset: 0))",
|
||||
"Test.java:1:73: compiler.err.cant.resolve.location.args: kindname.method, unknown, , , (compiler.misc.location: kindname.class, java.lang.String, null)",
|
||||
"2 errors"
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user