"VerifyError: Accessing value from uninitialized register" when using ASM and javaagent to collect method arguments
"VerifyError: Accessing value from uninitialized register" when using ASM and javaagent to collect method arguments
进入一个方法时,我想记录那个方法的所有参数。由于 ASM 很难调试,我写了一些演示代码(使用@apangin 的收集器 class)并测试其有效性。但是,当我使用以下代码时,它报告 java.lang.VerifyError: (class: com/D, method: add signature: (II)I) Accessing value from uninitialized register 2
。
我认为在创建框架时,局部变量由this
和方法的参数初始化。但是register 2
(我猜是局部变量中的第三个元素)应该由第二个int参数初始化,为什么它仍然抛出错误?
com/D代码:
public class D extends C {
public D() { }
public int a = 4;
@Override
public int p() { return a; }
public static int add(int a, int b){
return a+b;
}
}
我的methodVisitor适配器中的visitCode
方法class:
public void visitCode() {
mv.visitCode();
if (needAnalysePurity){
pushArgArrToStackInMeth();
mv.visitInsn(POP);
}
}
public void pushArgArrToStackInMeth(){
Type[] args = Type.getArgumentTypes(this.selfDesc);
// new ArgumentCollector(N)
String collector = Type.getInternalName(ArgCollectorLocals.class);
mv.visitTypeInsn(NEW, collector);
mv.visitInsn(DUP);
mv.visitIntInsn(SIPUSH, args.length);
mv.visitMethodInsn(INVOKESPECIAL, collector, "<init>", "(I)V", false);
// for each argument call the corresponding collector.add(arg)
int index = 1;
for (Type arg : args) {
String argDesc = arg.getDescriptor();
if (argDesc.length() > 1) {
argDesc = "Ljava/lang/Object;";
}
mv.visitVarInsn(arg.getOpcode(ILOAD), index);
mv.visitMethodInsn(INVOKEVIRTUAL, collector, "add", "(" + argDesc + ")L" + collector + ";", false);
index += arg.getSize();
}
// collector.toArray()
mv.visitMethodInsn(INVOKEVIRTUAL, collector, "toArray", "()[Ljava/lang/Object;", false);
}
用于收集参数的收集器class:
public class ArgCollectorLocals {
private final Object[] args;
private int index;
public ArgCollectorLocals(int length) {
this.args = new Object[length];
}
public ArgCollectorLocals add(boolean a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(byte a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(char a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(short a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(int a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(long a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(float a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(double a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(Object a) {
args[index++] = a;
return this;
}
public Object[] toArray() {
return args;
}
}
感谢@apangin,我终于解决了这个问题。除了方法参数之外,我还想记录方法所属的实例(如果方法不是静态的),所以我有以下代码:
public void pushArgArrToStackInMeth(){
Type[] args = Type.getArgumentTypes(this.selfDesc);
// new ArgumentCollector(N)
String collector = Type.getInternalName(ArgCollectorLocals.class);
mv.visitTypeInsn(NEW, collector);
mv.visitInsn(DUP);
if (isStatic){
mv.visitIntInsn(SIPUSH, args.length);
}else{
mv.visitIntInsn(SIPUSH, args.length + 1); // for this
}
mv.visitMethodInsn(INVOKESPECIAL, collector, "<init>", "(I)V", false);
// record "this" if not static
if (!isStatic){
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, collector, "add", "(Ljava/lang/Object;)L" + collector + ";", false);
}
// for each argument call the corresponding collector.add(arg)
int index = 1;
if (isStatic){
index = 0;
}
for (Type arg : args) {
String argDesc = arg.getDescriptor();
if (argDesc.length() > 1) {
argDesc = "Ljava/lang/Object;";
}
mv.visitVarInsn(arg.getOpcode(ILOAD), index);
mv.visitMethodInsn(INVOKEVIRTUAL, collector, "add", "(" + argDesc + ")L" + collector + ";", false);
index += arg.getSize();
}
// collector.toArray()
mv.visitMethodInsn(INVOKEVIRTUAL, collector, "toArray", "()[Ljava/lang/Object;", false);
}
进入一个方法时,我想记录那个方法的所有参数。由于 ASM 很难调试,我写了一些演示代码(使用@apangin 的收集器 class)并测试其有效性。但是,当我使用以下代码时,它报告 java.lang.VerifyError: (class: com/D, method: add signature: (II)I) Accessing value from uninitialized register 2
。
我认为在创建框架时,局部变量由this
和方法的参数初始化。但是register 2
(我猜是局部变量中的第三个元素)应该由第二个int参数初始化,为什么它仍然抛出错误?
com/D代码:
public class D extends C {
public D() { }
public int a = 4;
@Override
public int p() { return a; }
public static int add(int a, int b){
return a+b;
}
}
我的methodVisitor适配器中的visitCode
方法class:
public void visitCode() {
mv.visitCode();
if (needAnalysePurity){
pushArgArrToStackInMeth();
mv.visitInsn(POP);
}
}
public void pushArgArrToStackInMeth(){
Type[] args = Type.getArgumentTypes(this.selfDesc);
// new ArgumentCollector(N)
String collector = Type.getInternalName(ArgCollectorLocals.class);
mv.visitTypeInsn(NEW, collector);
mv.visitInsn(DUP);
mv.visitIntInsn(SIPUSH, args.length);
mv.visitMethodInsn(INVOKESPECIAL, collector, "<init>", "(I)V", false);
// for each argument call the corresponding collector.add(arg)
int index = 1;
for (Type arg : args) {
String argDesc = arg.getDescriptor();
if (argDesc.length() > 1) {
argDesc = "Ljava/lang/Object;";
}
mv.visitVarInsn(arg.getOpcode(ILOAD), index);
mv.visitMethodInsn(INVOKEVIRTUAL, collector, "add", "(" + argDesc + ")L" + collector + ";", false);
index += arg.getSize();
}
// collector.toArray()
mv.visitMethodInsn(INVOKEVIRTUAL, collector, "toArray", "()[Ljava/lang/Object;", false);
}
用于收集参数的收集器class:
public class ArgCollectorLocals {
private final Object[] args;
private int index;
public ArgCollectorLocals(int length) {
this.args = new Object[length];
}
public ArgCollectorLocals add(boolean a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(byte a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(char a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(short a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(int a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(long a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(float a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(double a) {
args[index++] = a;
return this;
}
public ArgCollectorLocals add(Object a) {
args[index++] = a;
return this;
}
public Object[] toArray() {
return args;
}
}
感谢@apangin,我终于解决了这个问题。除了方法参数之外,我还想记录方法所属的实例(如果方法不是静态的),所以我有以下代码:
public void pushArgArrToStackInMeth(){
Type[] args = Type.getArgumentTypes(this.selfDesc);
// new ArgumentCollector(N)
String collector = Type.getInternalName(ArgCollectorLocals.class);
mv.visitTypeInsn(NEW, collector);
mv.visitInsn(DUP);
if (isStatic){
mv.visitIntInsn(SIPUSH, args.length);
}else{
mv.visitIntInsn(SIPUSH, args.length + 1); // for this
}
mv.visitMethodInsn(INVOKESPECIAL, collector, "<init>", "(I)V", false);
// record "this" if not static
if (!isStatic){
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, collector, "add", "(Ljava/lang/Object;)L" + collector + ";", false);
}
// for each argument call the corresponding collector.add(arg)
int index = 1;
if (isStatic){
index = 0;
}
for (Type arg : args) {
String argDesc = arg.getDescriptor();
if (argDesc.length() > 1) {
argDesc = "Ljava/lang/Object;";
}
mv.visitVarInsn(arg.getOpcode(ILOAD), index);
mv.visitMethodInsn(INVOKEVIRTUAL, collector, "add", "(" + argDesc + ")L" + collector + ";", false);
index += arg.getSize();
}
// collector.toArray()
mv.visitMethodInsn(INVOKEVIRTUAL, collector, "toArray", "()[Ljava/lang/Object;", false);
}