[
https://issues.jboss.org/browse/JASSIST-222?page=com.atlassian.jira.plugi...
]
Manuel Geffken updated JASSIST-222:
-----------------------------------
Description:
The class S in the "boyer" benchmark of the Ashes Suite Collection
(
http://www.sable.mcgill.ca/ashes/) (no original source code available) has the following
bytecode according to javap:
{noformat}
Classfile ashesSuiteCollection/suites/ashesHardTestSuite/benchmarks/boyer/classes/S.class
Last modified May 2, 2014; size 154 bytes
MD5 checksum e79a1481a39d40004bc504cc4f7c2641
class S
minor version: 3
major version: 45
flags: ACC_SUPER
Constant pool:
...
{
protected int $;
flags: ACC_PROTECTED
protected S(int);
flags: ACC_PROTECTED
Code:
stack=3, locals=2, args_size=2
0: aload_0
1: iload_1
2: aload_0
3: invokespecial #14 // Method
java/lang/Object."<init>":()V
6: putfield #13 // Field $:I
9: return
}
{noformat}
An instrumentation of this class' constructor with a try/catch block as in
{noformat}
CtConstructor[] ctors = target.getDeclaredConstructors();
for (CtConstructor ctor : ctors) {
StringBuilder headerSB = new StringBuilder();
headerSB.append("{");
headerSB.append(" try {");
headerSB.append(" throw new java.lang.Exception();");
headerSB.append(" } catch(java.lang.Exception e) {}");
headerSB.append("}");
ctor.insertBeforeBody(headerSB.toString());
}
{noformat}
causes an invalid class file that _does not verify_:
{noformat}
Classfile
ashesSuiteCollection/suites/ashesHardTestSuite/benchmarks/boyer/out_classes/S_instr_error.class
Last modified May 5, 2014; size 356 bytes
MD5 checksum d4ef556ee82cee6c4c2960b43d7e71e1
class S
minor version: 3
major version: 45
flags: ACC_SUPER
Constant pool:
...
{
protected int $;
flags: ACC_PROTECTED
protected S(int);
flags: ACC_PROTECTED
Code:
stack=5, locals=3, args_size=2
0: aload_0
1: iload_1
2: aload_0
3: invokespecial #14 // Method
java/lang/Object."<init>":()V
6: new #22 // class java/lang/Exception
9: dup
10: invokespecial #23 // Method
java/lang/Exception."<init>":()V
13: athrow
14: astore_2
15: goto 18
18: putfield #13 // Field $:I
21: return
Exception table:
from to target type
6 14 14 Class java/lang/Exception
}
{noformat}
The problem is that the operand stack can be empty when the putfield instruction is
reached. The problem seems to be rooted in the fact that the original bytecode sequence
assumes that the two entries of the operand stack reach the {{putfield}} instruction.
However, this assumption is invalid in the instrumented code.
In contrast the reconstructed source code (the original source is not available)
{noformat}
class S {
int $;
public S(int i) {
$ = i;
}
}
{noformat}
compiled with javac 1.7.0_51 ({{javac -source 1.3 -target 1.1}}) produces
{noformat}
Classfile S.class
Last modified May 5, 2014; size 222 bytes
MD5 checksum 9700e6458db9d62e640018421a079761
Compiled from "S.java"
public class S
SourceFile: "S.java"
minor version: 3
major version: 45
flags: ACC_SUPER
Constant pool:
...
{
int $;
flags:
public S(int);
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: invokespecial #1 // Method
java/lang/Object."<init>":()V
4: aload_0
5: iload_1
6: putfield #2 // Field $:I
9: return
}
{noformat}
This version can be instrumented as shown above without problems. Here the operand of the
putfield instruction are pushed on the stack _after_ the {{invokespecial}} instruction.
{noformat}
1: invokespecial #1 // Method
java/lang/Object."<init>":()V
4: aload_0
5: iload_1
{noformat}
This sequence seems easier to instrument (after the super call) with code containing a
try/catch block.
was:
The class S in the "boyer" benchmark of the Ashes Suite Collection
(
http://www.sable.mcgill.ca/ashes/) (no original source code available) has the following
bytecode according to javap:
{noformat}
Classfile ashesSuiteCollection/suites/ashesHardTestSuite/benchmarks/boyer/classes/S.class
Last modified May 2, 2014; size 154 bytes
MD5 checksum e79a1481a39d40004bc504cc4f7c2641
class S
minor version: 3
major version: 45
flags: ACC_SUPER
Constant pool:
...
{
protected int $;
flags: ACC_PROTECTED
protected S(int);
flags: ACC_PROTECTED
Code:
stack=3, locals=2, args_size=2
0: aload_0
1: iload_1
2: aload_0
3: invokespecial #14 // Method
java/lang/Object."<init>":()V
6: putfield #13 // Field $:I
9: return
}
{noformat}
An instrumentation of this class' constructor with a try/catch block as in
{noformat}
CtConstructor[] ctors = target.getDeclaredConstructors();
for (CtConstructor ctor : ctors) {
StringBuilder headerSB = new StringBuilder();
headerSB.append("{");
headerSB.append(" try {");
headerSB.append(" throw new java.lang.Exception();");
headerSB.append(" } catch(java.lang.Exception e) {}");
headerSB.append("}");
ctor.insertBeforeBody(headerSB.toString());
}
{noformat}
causes an invalid class file that _does not verify_:
{noformat}
Classfile
ashesSuiteCollection/suites/ashesHardTestSuite/benchmarks/boyer/out_classes/S_instr_error.class
Last modified May 5, 2014; size 356 bytes
MD5 checksum d4ef556ee82cee6c4c2960b43d7e71e1
class S
minor version: 3
major version: 45
flags: ACC_SUPER
Constant pool:
...
{
protected int $;
flags: ACC_PROTECTED
protected S(int);
flags: ACC_PROTECTED
Code:
stack=5, locals=3, args_size=2
0: aload_0
1: iload_1
2: aload_0
3: invokespecial #14 // Method
java/lang/Object."<init>":()V
6: new #22 // class java/lang/Exception
9: dup
10: invokespecial #23 // Method
java/lang/Exception."<init>":()V
13: athrow
14: astore_2
15: goto 18
18: putfield #13 // Field $:I
21: return
Exception table:
from to target type
6 14 14 Class java/lang/Exception
}
{noformat}
The problem is that the operand stack can be empty when the putfield instruction is
reached. The problem seems to be rooted in the fact that the original bytecode sequence
assumes that the two entries of the operand stack reach the {{putfield}} instruction.
However, this assumption is invalid in the instrumented code.
In contrast the reconstructed source code (the original source is not available)
{noformat}
class S {
int $;
public S(int i) {
$ = i;
}
}
{noformat}
compiled with javac 1.7.0_51 ({{javac -source 1.3 -target 1.1}}) produces
{noformat}
Classfile S.class
Last modified May 5, 2014; size 222 bytes
MD5 checksum 9700e6458db9d62e640018421a079761
Compiled from "S.java"
public class S
SourceFile: "S.java"
minor version: 3
major version: 45
flags: ACC_SUPER
Constant pool:
...
{
int $;
flags:
public S(int);
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: invokespecial #1 // Method
java/lang/Object."<init>":()V
4: aload_0
5: iload_1
6: putfield #2 // Field $:I
9: return
}
{noformat}
This version can be instrumented as shown above without problems. Here the operand of the
putfield instruction are pushed on the stack _after_ the {{putfield}} instruction.
{noformat}
1: invokespecial #1 // Method
java/lang/Object."<init>":()V
4: aload_0
5: iload_1
{noformat}
This sequence seems easier to instrument (after the super call) with code containing a
try/catch block.
Using insertBeforeBody to insert try/catch block in constructor can
generate invalid bytecode for certain Java compilers
------------------------------------------------------------------------------------------------------------------------
Key: JASSIST-222
URL:
https://issues.jboss.org/browse/JASSIST-222
Project: Javassist
Issue Type: Bug
Affects Versions: 3.18.0-GA
Environment: Unknown java compiler generating class files with major version 45,
minor version 3.
Mint Linux, JDK 1.7.
Reporter: Manuel Geffken
Assignee: Shigeru Chiba
Priority: Minor
Attachments: S.class, S.java, S_instr_error.class, S_instr_success.class
The class S in the "boyer" benchmark of the Ashes Suite Collection
(
http://www.sable.mcgill.ca/ashes/) (no original source code available) has the following
bytecode according to javap:
{noformat}
Classfile
ashesSuiteCollection/suites/ashesHardTestSuite/benchmarks/boyer/classes/S.class
Last modified May 2, 2014; size 154 bytes
MD5 checksum e79a1481a39d40004bc504cc4f7c2641
class S
minor version: 3
major version: 45
flags: ACC_SUPER
Constant pool:
...
{
protected int $;
flags: ACC_PROTECTED
protected S(int);
flags: ACC_PROTECTED
Code:
stack=3, locals=2, args_size=2
0: aload_0
1: iload_1
2: aload_0
3: invokespecial #14 // Method
java/lang/Object."<init>":()V
6: putfield #13 // Field $:I
9: return
}
{noformat}
An instrumentation of this class' constructor with a try/catch block as in
{noformat}
CtConstructor[] ctors = target.getDeclaredConstructors();
for (CtConstructor ctor : ctors) {
StringBuilder headerSB = new StringBuilder();
headerSB.append("{");
headerSB.append(" try {");
headerSB.append(" throw new java.lang.Exception();");
headerSB.append(" } catch(java.lang.Exception e) {}");
headerSB.append("}");
ctor.insertBeforeBody(headerSB.toString());
}
{noformat}
causes an invalid class file that _does not verify_:
{noformat}
Classfile
ashesSuiteCollection/suites/ashesHardTestSuite/benchmarks/boyer/out_classes/S_instr_error.class
Last modified May 5, 2014; size 356 bytes
MD5 checksum d4ef556ee82cee6c4c2960b43d7e71e1
class S
minor version: 3
major version: 45
flags: ACC_SUPER
Constant pool:
...
{
protected int $;
flags: ACC_PROTECTED
protected S(int);
flags: ACC_PROTECTED
Code:
stack=5, locals=3, args_size=2
0: aload_0
1: iload_1
2: aload_0
3: invokespecial #14 // Method
java/lang/Object."<init>":()V
6: new #22 // class java/lang/Exception
9: dup
10: invokespecial #23 // Method
java/lang/Exception."<init>":()V
13: athrow
14: astore_2
15: goto 18
18: putfield #13 // Field $:I
21: return
Exception table:
from to target type
6 14 14 Class java/lang/Exception
}
{noformat}
The problem is that the operand stack can be empty when the putfield instruction is
reached. The problem seems to be rooted in the fact that the original bytecode sequence
assumes that the two entries of the operand stack reach the {{putfield}} instruction.
However, this assumption is invalid in the instrumented code.
In contrast the reconstructed source code (the original source is not available)
{noformat}
class S {
int $;
public S(int i) {
$ = i;
}
}
{noformat}
compiled with javac 1.7.0_51 ({{javac -source 1.3 -target 1.1}}) produces
{noformat}
Classfile S.class
Last modified May 5, 2014; size 222 bytes
MD5 checksum 9700e6458db9d62e640018421a079761
Compiled from "S.java"
public class S
SourceFile: "S.java"
minor version: 3
major version: 45
flags: ACC_SUPER
Constant pool:
...
{
int $;
flags:
public S(int);
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: invokespecial #1 // Method
java/lang/Object."<init>":()V
4: aload_0
5: iload_1
6: putfield #2 // Field $:I
9: return
}
{noformat}
This version can be instrumented as shown above without problems. Here the operand of the
putfield instruction are pushed on the stack _after_ the {{invokespecial}} instruction.
{noformat}
1: invokespecial #1 // Method
java/lang/Object."<init>":()V
4: aload_0
5: iload_1
{noformat}
This sequence seems easier to instrument (after the super call) with code containing a
try/catch block.
--
This message was sent by Atlassian JIRA
(v6.2.3#6260)