|
|
|
|
@ -88,6 +88,9 @@ public class ClassReader {
@@ -88,6 +88,9 @@ public class ClassReader {
|
|
|
|
|
*/ |
|
|
|
|
static final int EXPAND_ASM_INSNS = 256; |
|
|
|
|
|
|
|
|
|
/** The maximum size of array to allocate. */ |
|
|
|
|
private static final int MAX_BUFFER_SIZE = 1024 * 1024; |
|
|
|
|
|
|
|
|
|
/** The size of the temporary byte array used to read class input streams chunk by chunk. */ |
|
|
|
|
private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096; |
|
|
|
|
|
|
|
|
|
@ -310,13 +313,19 @@ public class ClassReader {
@@ -310,13 +313,19 @@ public class ClassReader {
|
|
|
|
|
if (inputStream == null) { |
|
|
|
|
throw new IOException("Class not found"); |
|
|
|
|
} |
|
|
|
|
int bufferSize = calculateBufferSize(inputStream); |
|
|
|
|
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { |
|
|
|
|
byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE]; |
|
|
|
|
byte[] data = new byte[bufferSize]; |
|
|
|
|
int bytesRead; |
|
|
|
|
while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) { |
|
|
|
|
int readCount = 0; |
|
|
|
|
while ((bytesRead = inputStream.read(data, 0, bufferSize)) != -1) { |
|
|
|
|
outputStream.write(data, 0, bytesRead); |
|
|
|
|
readCount++; |
|
|
|
|
} |
|
|
|
|
outputStream.flush(); |
|
|
|
|
if (readCount == 1) { |
|
|
|
|
return data; |
|
|
|
|
} |
|
|
|
|
return outputStream.toByteArray(); |
|
|
|
|
} finally { |
|
|
|
|
if (close) { |
|
|
|
|
@ -325,6 +334,20 @@ public class ClassReader {
@@ -325,6 +334,20 @@ public class ClassReader {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static int calculateBufferSize(final InputStream inputStream) throws IOException { |
|
|
|
|
int expectedLength = inputStream.available(); |
|
|
|
|
/* |
|
|
|
|
* Some implementations can return 0 while holding available data |
|
|
|
|
* (e.g. new FileInputStream("/proc/a_file")) |
|
|
|
|
* Also in some pathological cases a very small number might be returned, |
|
|
|
|
* and in this case we use default size |
|
|
|
|
*/ |
|
|
|
|
if (expectedLength < 256) { |
|
|
|
|
return INPUT_STREAM_DATA_CHUNK_SIZE; |
|
|
|
|
} |
|
|
|
|
return Math.min(expectedLength, MAX_BUFFER_SIZE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
|
// Accessors
|
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
|
|
|
@ -3456,7 +3479,6 @@ public class ClassReader {
@@ -3456,7 +3479,6 @@ public class ClassReader {
|
|
|
|
|
private int[] readBootstrapMethodsAttribute(final int maxStringLength) { |
|
|
|
|
char[] charBuffer = new char[maxStringLength]; |
|
|
|
|
int currentAttributeOffset = getFirstAttributeOffset(); |
|
|
|
|
int[] currentBootstrapMethodOffsets = null; |
|
|
|
|
for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) { |
|
|
|
|
// Read the attribute_info's attribute_name and attribute_length fields.
|
|
|
|
|
String attributeName = readUTF8(currentAttributeOffset, charBuffer); |
|
|
|
|
@ -3464,17 +3486,17 @@ public class ClassReader {
@@ -3464,17 +3486,17 @@ public class ClassReader {
|
|
|
|
|
currentAttributeOffset += 6; |
|
|
|
|
if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) { |
|
|
|
|
// Read the num_bootstrap_methods field and create an array of this size.
|
|
|
|
|
currentBootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)]; |
|
|
|
|
int[] result = new int[readUnsignedShort(currentAttributeOffset)]; |
|
|
|
|
// Compute and store the offset of each 'bootstrap_methods' array field entry.
|
|
|
|
|
int currentBootstrapMethodOffset = currentAttributeOffset + 2; |
|
|
|
|
for (int j = 0; j < currentBootstrapMethodOffsets.length; ++j) { |
|
|
|
|
currentBootstrapMethodOffsets[j] = currentBootstrapMethodOffset; |
|
|
|
|
for (int j = 0; j < result.length; ++j) { |
|
|
|
|
result[j] = currentBootstrapMethodOffset; |
|
|
|
|
// Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each),
|
|
|
|
|
// as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2).
|
|
|
|
|
currentBootstrapMethodOffset += |
|
|
|
|
4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2; |
|
|
|
|
} |
|
|
|
|
return currentBootstrapMethodOffsets; |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
currentAttributeOffset += attributeLength; |
|
|
|
|
} |
|
|
|
|
|