Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
尝试插入java字节码时堆栈中的参数数目错误_Java_Bytecode_Instrumentation - Fatal编程技术网

尝试插入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后缀检测对我的

我正在开发一个小型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
后缀检测对我的方法的所有构造函数调用

下面您可以看到
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;
    }
}