Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BCEL-341: Oak class file patch #58

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@
<contributor>
<name>Sam Yoon</name>
</contributor>

<contributor>
<name>Hippo</name>
<email>hippah at protonmail.com</email>
</contributor>
</contributors>

<mailingLists>
Expand Down
25 changes: 24 additions & 1 deletion src/main/java/org/apache/bcel/classfile/Attribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ protected static void println(final String msg) {
}
}


/**
* Class method reads one attribute from the input data stream. This method
* must not be accessible from the outside. It is called by the Field and
Expand All @@ -110,6 +111,28 @@ protected static void println(final String msg) {
*/
public static Attribute readAttribute(final DataInput file, final ConstantPool constant_pool)
throws IOException, ClassFormatException
{
return readAttribute(file, constant_pool, false);
}

/**
* Class method reads one attribute from the input data stream. This method
* must not be accessible from the outside. It is called by the Field and
* Method constructor methods.
*
* @see Field
* @see Method
*
* @param file Input stream
* @param constant_pool Array of constants
* @param isOak If the the class file is oak
* @return Attribute
* @throws IOException
* @throws ClassFormatException
* @since 6.0
*/
public static Attribute readAttribute(final DataInput file, final ConstantPool constant_pool, final boolean isOak)
throws IOException, ClassFormatException
{
byte tag = Const.ATTR_UNKNOWN; // Unknown attribute
// Get class name from constant pool via `name_index' indirection
Expand Down Expand Up @@ -145,7 +168,7 @@ public static Attribute readAttribute(final DataInput file, final ConstantPool c
case Const.ATTR_SOURCE_FILE:
return new SourceFile(name_index, length, file, constant_pool);
case Const.ATTR_CODE:
return new Code(name_index, length, file, constant_pool);
return new Code(name_index, length, file, constant_pool, isOak);
case Const.ATTR_EXCEPTIONS:
return new ExceptionTable(name_index, length, file, constant_pool);
case Const.ATTR_LINE_NUMBER_TABLE:
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/org/apache/bcel/classfile/ClassParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public final class ClassParser {
private Attribute[] attributes; // attributes defined in the class
private final boolean isZip; // Loaded from zip file
private static final int BUFSIZE = 8192;
private boolean isOak; // Is oak class file


/**
Expand Down Expand Up @@ -290,7 +291,7 @@ private void readMethods() throws IOException, ClassFormatException {
final int methods_count = dataInputStream.readUnsignedShort();
methods = new Method[methods_count];
for (int i = 0; i < methods_count; i++) {
methods[i] = new Method(dataInputStream, constantPool);
methods[i] = new Method(dataInputStream, constantPool, isOak);
}
}

Expand All @@ -303,5 +304,6 @@ private void readMethods() throws IOException, ClassFormatException {
private void readVersion() throws IOException, ClassFormatException {
minor = dataInputStream.readUnsignedShort();
major = dataInputStream.readUnsignedShort();
isOak = major < Const.MAJOR_1_1 || (major == Const.MAJOR_1_1 && minor < 3);
Copy link
Member

@garydgregory garydgregory Aug 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the check be minor <= 3 instead? See notes.
Are you saying that 45.2 is not compatible with 45.3?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OakFile.java.zip
There is no license, it's practically a hello world program.

Hi @Hippo
I'll should be able to take a look this weekend to see if a cleaner approach can be devised. In the meantime, please provide the source .java and instructions on how you created the class file if it is out of the ordinary Java tooling we are all used to. Is there an Oak/Java 1.0 compiler you used we can download to create additional files?

No I don't have an oak compiler, but you can emulate one by transforming a class file and changing its version to a proper oak version and halfing the correct data types in the code attribute.

Copy link
Author

@Hippo Hippo Aug 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the check be minor <= 3 instead? See notes.
Are you saying that 45.2 is not compatible with 45.3?

No it should be minor < 3 take a look at the jvm's class parser
https://github.com/AdoptOpenJDK/openjdk-jdk8u/blob/4b69552faa8de8f7de5bed1c95c12c025702b8ee/hotspot/src/share/vm/classfile/classFileParser.cpp#L2137

Also I check major < Const.MAJOR_1_1 just in-case the major version is less than 45, which shouldn't happen, but it's there just in-case.

}
}
66 changes: 58 additions & 8 deletions src/main/java/org/apache/bcel/classfile/Code.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public final class Code extends Attribute {
private byte[] code; // Actual byte code
private CodeException[] exceptionTable; // Table of handled exceptions
private Attribute[] attributes; // or LocalVariable
private boolean isOak; // If the class file follows oak format


/**
Expand All @@ -60,6 +61,7 @@ public Code(final Code c) {
}



/**
* @param name_index Index pointing to the name <em>Code</em>
* @param length Content length in bytes
Expand All @@ -68,10 +70,23 @@ public Code(final Code c) {
*/
Code(final int name_index, final int length, final DataInput file, final ConstantPool constant_pool)
throws IOException {
this(name_index, length, file, constant_pool, false);
}

/**
* @param name_index Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param file Input stream
* @param constant_pool Array of constants
* @param isOak If the class file is oak
*/
Code(final int name_index, final int length, final DataInput file, final ConstantPool constant_pool, final boolean isOak)
throws IOException {
// Initialize with some default values which will be overwritten later
this(name_index, length, file.readUnsignedShort(), file.readUnsignedShort(), (byte[]) null,
(CodeException[]) null, (Attribute[]) null, constant_pool);
final int code_length = file.readInt();
this(name_index, length, isOak ? file.readUnsignedByte() : file.readUnsignedShort(), isOak ? file.readUnsignedByte() : file.readUnsignedShort(),
(byte[]) null, (CodeException[]) null, (Attribute[]) null, constant_pool);
this.isOak = isOak;
final int code_length = isOak ? file.readUnsignedShort() : file.readInt();
code = new byte[code_length]; // Read byte code
file.readFully(code);
/* Read exception table that contains all regions where an exception
Expand Down Expand Up @@ -109,13 +124,30 @@ public Code(final Code c) {
* @param constant_pool Array of constants
*/
public Code(final int name_index, final int length, final int maxStack, final int maxLocals, final byte[] code,
final CodeException[] exceptionTable, final Attribute[] attributes, final ConstantPool constant_pool) {
final CodeException[] exceptionTable, final Attribute[] attributes, final ConstantPool constant_pool) {
this(name_index, length, maxStack, maxLocals, code, exceptionTable, attributes, constant_pool, false);
}

/**
* @param name_index Index pointing to the name <em>Code</em>
* @param length Content length in bytes
* @param maxStack Maximum size of stack
* @param maxLocals Number of local variables
* @param code Actual byte code
* @param exceptionTable of handled exceptions
* @param attributes Attributes of code: LineNumber or LocalVariable
* @param constant_pool Array of constants
* @param isOak If the class file follows the oak format
*/
public Code(final int name_index, final int length, final int maxStack, final int maxLocals, final byte[] code,
final CodeException[] exceptionTable, final Attribute[] attributes, final ConstantPool constant_pool, final boolean isOak) {
super(Const.ATTR_CODE, name_index, length, constant_pool);
this.maxStack = maxStack;
this.maxLocals = maxLocals;
this.code = code != null ? code : ArrayUtils.EMPTY_BYTE_ARRAY;
this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY;
this.attributes = attributes != null ? attributes : EMPTY_ATTRIBUTE_ARRAY;
this.isOak = isOak;
super.setLength(calculateLength()); // Adjust length
}

Expand All @@ -142,9 +174,15 @@ public void accept( final Visitor v ) {
@Override
public void dump( final DataOutputStream file ) throws IOException {
super.dump(file);
file.writeShort(maxStack);
file.writeShort(maxLocals);
file.writeInt(code.length);
if (isOak) {
file.writeByte(maxStack);
file.writeByte(maxLocals);
file.writeShort(code.length);
} else {
file.writeShort(maxStack);
file.writeShort(maxLocals);
file.writeInt(code.length);
}
file.write(code, 0, code.length);
file.writeShort(exceptionTable.length);
for (final CodeException exception : exceptionTable) {
Expand Down Expand Up @@ -230,7 +268,19 @@ public int getMaxStack() {
* and excluding all its attributes
*/
private int getInternalLength() {
return 2 /*maxStack*/+ 2 /*maxLocals*/+ 4 /*code length*/
final int maxStack;
final int maxLocals;
final int codeLength;
if (isOak) {
maxStack = 1;
maxLocals = 1;
codeLength = 2;
} else {
maxStack = 2;
maxLocals = 2;
codeLength = 4;
}
return maxStack + maxLocals + codeLength
+ code.length /*byte-code*/
+ 2 /*exception-table length*/
+ 8 * (exceptionTable == null ? 0 : exceptionTable.length) /* exception table */
Expand Down
13 changes: 12 additions & 1 deletion src/main/java/org/apache/bcel/classfile/FieldOrMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,23 @@ protected FieldOrMethod(final DataInputStream file, final ConstantPool constant_
* @throws ClassFormatException
*/
protected FieldOrMethod(final DataInput file, final ConstantPool constant_pool) throws IOException, ClassFormatException {
this(file, constant_pool, false);
}

/**
* Construct object from file stream.
* @param file Input stream
* @param isOak If the class file is oak
* @throws IOException
* @throws ClassFormatException
*/
protected FieldOrMethod(final DataInput file, final ConstantPool constant_pool, final boolean isOak) throws IOException, ClassFormatException {
this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null,
constant_pool);
final int attributes_count = file.readUnsignedShort();
attributes = new Attribute[attributes_count];
for (int i = 0; i < attributes_count; i++) {
attributes[i] = Attribute.readAttribute(file, constant_pool);
attributes[i] = Attribute.readAttribute(file, constant_pool, isOak);
}
this.attributes_count = attributes_count; // init deprecated field
}
Expand Down
14 changes: 13 additions & 1 deletion src/main/java/org/apache/bcel/classfile/Method.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,19 @@ public Method(final Method c) {
*/
Method(final DataInput file, final ConstantPool constant_pool) throws IOException,
ClassFormatException {
super(file, constant_pool);
this(file, constant_pool, false);
}

/**
* Construct object from file stream.
* @param file Input stream
* @param isOak If the class file is oak
* @throws IOException
* @throws ClassFormatException
*/
Method(final DataInput file, final ConstantPool constant_pool, final boolean isOak) throws IOException,
ClassFormatException {
super(file, constant_pool, isOak);
}


Expand Down