繁体   English   中英

如何避免VerifyError:对于已初始化的对象,“期望在堆栈上找到统一的对象”

[英]How to avoid the VerifyError: “Expecting to find unitialized object on stack” for objects already initialized

我正在使用ASM开发一种检测引擎,我需要拦截方法的调用,这些方法接收数组类型的参数。 为此,我实现了MethodVisitor并在其visitMethodInsn检查desc参数是否指定任何数组类型的参数。 如果目标方法没有数组类型的参数,则无需执行任何操作,而是插入原始方法调用: super.visitMethodInsn(opcode, owner, name, desc);

另一方面,如果目标方法具有数组类型的参数,那么我必须对其参数执行特定的操作。 访问每个参数的最简单解决方案是调用具有目标方法相同描述符的中介方法,并且在此中介中,我可以轻松访问其参数(与传递给目标方法的参数相对应)。

但是,当目标方法是实例构造函数( <init> )时,就会出现问题。 在Java中, new XXX()转换为字节码,如下所示:

  NEW XXX 
  DUP 
  INVOKESPECIAL XXXX.<init>()

根据我上面说明的方法,我将INVOKESPECIAL调用移到了调解器方法中,新实例化的对象是此调解器的第一个参数。 但是,验证者为此调解器提出了一个错误,报告调解器的第一个参数(将成为目标方法的第一个参数- <init> )不是“统一对象”。 更准确地说,我得到了一个错误: Exception in thread "main" java.lang.VerifyError: Expecting to find unitialized object on stack”

一旦我将字节码NEWINVOKESPECIAL拆分为两种不同的方法,验证程序就会声明传递给INVOKESPECIAL的参数已被初始化。

有任何解决此问题的建议吗? (请不要回答我,以避免中介者直接访问堆栈中的参数,因为复制和替换在堆栈中占据任意位置的参数并不简单。)

验证者是否正确拒绝代码(请参阅JVM规范)。 无法绕过字节码验证程序。

一种解决方法是在构造函数调用时内联中介程序代码。 您仍然可以在调用构造函数之前或之后将调解器的某些部分作为方法调用来调用,但是构造函数的调用必须与新指令位于同一方法中。

另一种方法是为要实例化的每个类创建特殊的介体,因此介体会自己调用new指令以及构造函数调用。

如果现有的AOP库可以正确完成所需的工作,那么您也可以查看它们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM