我正在研究一个小的java字节码检测工具.
一般的想法是使用_CONGU后缀重命名所有类方法,然后使用将调用其_CONGU对应物的原始方法名称创建代理方法.
例如,如果类C包含int m(){return 1;方法,检测的C类将有一个int m_CONGU(){return 1; } method和int m(){return m_CONGU(); } 方法.
稍后我会在int m()上添加一些额外的逻辑,它们会在调用m_CONGU()之前进行一些检查.
目前,我正在使用_CONGU后缀将所有构造函数调用调用检测到我的方法.
在Bellow中,您可以看到Fraction类的inverse()方法的检测版本和非检测版本.
尝试运行此代码时
Fraction fraction = new Fraction(4,1);
我得到以下异常,这让我在过去几个小时里感到困惑:
Exception in thread “main” java.lang.VerifyError: (class:
jorgeTestes/system/fraction/Fraction,method: inverse_CONGU signature:
()LjorgeTestes/system/fraction/Fraction;) Expecting to find
object/array on stack at
jorgeTestes.system.fraction.XyzTest.main(XyzTest.java:9)
我想这肯定是一个明显的错误,但我无法得到问题所在.它看起来在某种程度上与堆栈中包含错误数量的数据有关,但它在我看来堆栈中的元素数量在原始代码和已检测代码上都是相同的(至少应该发生的是这样) ).有任何想法吗?
更多信息:
1)这里是< init>的描述符.和Fraction_CONGU(正如人们所期望的那样!):
2)我想知道Bytecode Viewer中[0]代码的颜色是否不同可能意味着我的检测代码存在其他问题?也许有一些元数据在这个过程中被破坏了,所以这可能是代码看起来不错的原因,并且在尝试运行代码时仍然存在问题?
new #1
你基本上做的是:在堆上分配一些原始(可能是零)内存并对该内存块调用虚方法Fraction_congu.你还没有调用构造函数!
还应该有invokevirtual,我猜这个生成的方法是私有的.
更新:我假设您要转换以下类:
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;
}
}
如你所见,这是完全可能的(如果我的想法正确).只需编译此Java代码,看看编译器如何实现它.
这引出了一个问题:你不能只使用AspectJ进行编译时编织吗?