尝试插入java字节码时堆栈中的参数数目错误
我正在开发一个小型java字节码检测工具 总体思路是使用尝试插入java字节码时堆栈中的参数数目错误,java,bytecode,instrumentation,Java,Bytecode,Instrumentation,我正在开发一个小型java字节码检测工具 总体思路是使用\u CONGU后缀重命名所有类方法,然后使用原始方法名创建代理方法,这些方法将调用它们的\u CONGU对应项 例如,如果类C包含int m(){return 1;}方法,则插入指令的C类将具有int m_CONGU(){return 1;}方法和int m(){return m_CONGU();}方法 稍后,我将在int m()上添加一些额外的逻辑,在调用m_CONGU()之前进行一些检查 目前,我正在使用\u CONGU后缀检测对我的
\u CONGU
后缀重命名所有类方法,然后使用原始方法名创建代理方法,这些方法将调用它们的\u CONGU
对应项
例如,如果类C
包含int m(){return 1;}
方法,则插入指令的C
类将具有int m_CONGU(){return 1;}
方法和int m(){return m_CONGU();}
方法
稍后,我将在int m()
上添加一些额外的逻辑,在调用m_CONGU()
之前进行一些检查
目前,我正在使用\u CONGU
后缀检测对我的方法的所有构造函数调用
下面您可以看到Fraction
类的inverse()
方法的插入指令版本和未插入指令版本。
尝试运行此代码时
Fraction fraction = new Fraction(4, 1);
在过去的几个小时里,我遇到了以下让我困惑的异常情况:
线程“main”java.lang.VerifyError中出现异常:(类:
jorgeTestes/系统/分数/分数,方法:逆康古签名:
()LjorgeTestes/system/fraction/fraction;)希望找到
堆栈上的对象/数组位于
jorgeTestes.system.fraction.XyzTest.main(XyzTest.java:9)
我想这一定是个非常明显的错误,但我不知道问题出在哪里。它看起来在某种程度上与堆栈中的数据数量错误有关,但在我看来,堆栈中的元素数量在原始代码和插入指令的代码中都是相同的(至少应该是这样)。有什么想法吗
更多信息:
1) 以下是
和分数的描述符(正如人们所期望的那样,它们是相同的!):
2) 我想知道字节码查看器中[0]代码的颜色不同是否意味着插入指令的代码存在其他问题?也许在这个过程中有一些元数据被破坏了,所以这可能是代码看起来正常的原因,并且在尝试运行代码时仍然存在问题?看起来第一个屏幕截图上的代码基本上被破坏了。JVM字节码中的对象构造可以分为两个阶段:在堆上分配内存和针对分配的内存调用构造函数(带有可选参数):
new #1 <Fraction> //allocate memory
dup //duplicate to not loose the object after calling constructor
//push c-tor args onto the stack here
invokespecial <Fraction.<init>> //constructor, second `this` is lost
areturn //returns first `this`
进入:
正如你所看到的,这是完全可能的(如果我理解正确的话)。只需编译这段Java代码,看看编译器是如何实现的
这就引出了一个问题:难道不能在编译时编织中使用AspectJ吗?在插入指令时,需要使用特殊情况的构造函数和对构造函数的调用
请注意,插入指令的调用invokevirtual,而未插入指令的调用invokespecial
新操作码返回的堆栈上的对象不能由invokespecial以外的任何操作码处理。Argh,您是对的。这就引出了一个问题,那就是我想做的事情是否真的可以这样做。(顺便说一句,目前生成的_CONGU方法是公开的)@OmnumeDelysum:请看我的更新,我认为这是完全可能的。只是一件小事,在调用special之前需要c-tor参数。@TomaszNurkiewicz:“这就引出了一个问题:你不能在编译时编织中使用AspectJ吗?”不幸的是,这不是我能决定的,我们在项目中已经取得了很大的进展:(@bestsss-你说得对,我在正确的地方添加了一条评论,谢谢!插入指令的版本调用invokevirtual,因为Fraction_CONGU()确实是一种方法。但是可能有Fraction_CONGU()作为一个构造函数可以解决我的问题..让构造函数调用a_CONGU()构造函数引发了如何使用相同参数生成另一个构造函数的问题!由于所有构造函数都具有相同的名称,我无法进行区分..您可以选择根本不检测构造函数或构造函数调用;另一个选择是使用单个无参数构造函数并用成员f替换所有构造函数调用此函数的函数。我确实需要插入指令的构造函数:-(。我不能有默认的非参数构造函数,因为这样会禁止客户端类本身有无参数构造函数!
class Fraction {
public Fraction(float den, float num) {
//original constructor code here
}
public int m() {
return 1;
}
}
class Fraction {
public Fraction(float den, float num) {
//proxy method
//place for extra logic
Fraction_CONGU(den, num);
}
private Fraction_CONGU(float den, float num) {
//original constructor code here
}
public int m() {
//proxy method
//place for extra logic
return m_CONGU
}
private int m_CONGU() {
return 1;
}
}