【发布时间】:2020-09-29 03:39:07
【问题描述】:
我正在使用 ASM(也使用树和实用程序)并且遇到了一个奇怪的异常
Exception in thread "main" java.lang.ClassFormatError: Invalid length 65526 in LocalVariableTable in class file
我正在尝试编辑 .class 文件的字节码,以生成新的。我有一个 for 循环,里面有一些 if 分支,我尝试修改它。我在两个 for 循环的代码下方发布了初始循环和所需生成的代码。
首字母
int[] ar = new int[]{1,2,3,4,5};
int[] ar2 = new int[]{8,9,9,94,3,2};
MyClass myar = new MyClass(ar);
MyClass myar2 = new MyClass(ar2);
int sum=0;
for(int i=0; i<ar.length; i++)
if(ar[i]>3) {
if(ar2[i]>8) {
sum+=(ar[i]+ar2[i]);
}
}
}
希望
int[] ar = new int[]{1,2,3,4,5};
int[] ar2 = new int[]{8,9,9,94,3,2};
MyClass myar = new MyClass(ar);
MyClass myar2 = new MyClass(ar2);
int sum=0;
for(int i=0; i<ar.length; i++)
int[] temp = callAFunctionToDoSthing(myar, myar2);
if(temp[0]>3) {
if(temp[1]>8) {
sum+=(temp[0]+temp[1]);
}else i+=1;
}else i+=2;
}
为了做到这一点,我使用 ASM 树 ListIterator 来检测 for 循环(我通过检查某些命令是否一个接一个地出现来做到这一点)。我使用 intellj 的 ASM 字节码扩展来比较初始字节码和所需字节码。然后,使用 ASM 树删除并在字节码列表中添加我想要的指令。 (我尝试过 ASM5 和 ASM8) 问题是,当我运行生成的 .class 文件时,在这个操作之后,我得到了上面的异常。 关键是我没有手动编辑 LocalVariableTable,也不知道如何编辑它。如果我在所需代码中运行 javap -v 命令,我什至看不到 LocalVariableTable,而如果我在生成的 .class 文件中运行 javap -v,我会看到它。
我尝试了另一种修改,以发现我对 ASM 树的想法可以在没有 if 和唯一数组的更简单的 for 循环中工作,并且在那里一切正常。
另外,我尝试过使用 SKIP_DEBUG,但我看不到 Label 和 LineNumber -Nodes,在我的情况下,我需要删除一些 LabelNode 和 LineNumberNode 指令。
编辑:
我正在举一个简单的例子来说明我进行转换的方式。我使用初始和所需 ASM 字节码的差异检查器,它会产生如下图所示的内容 所以为了操作的代码是
IntInsnNode bp7 = (IntInsnNode) aload17.getNext();
instructions.remove(bp7.getNext());
instructions.remove(bp7.getNext());
instructions.remove(bp7.getNext());
instructions.remove(bp7.getNext());
instructions.remove(bp7.getNext());
InsnList l4 = new InsnList();
LabelNode l45Ins = new LabelNode();
l4.add(new JumpInsnNode(Opcodes.IF_ICMPGT, l45Ins));
LabelNode l46Ins = new LabelNode();
l4.add(l46Ins);
l4.add(new LineNumberNode(178, l46Ins));
l4.add(new VarInsnNode(Opcodes.ALOAD, 20));
l4.add(new InsnNode(Opcodes.ICONST_0));
instructions.insert(bp7, l4);
【问题讨论】:
-
您是否尝试过使用 Krakatau 反汇编程序而不是
javap? Krakatau 应该让您更准确地了解类文件中的实际内容。 github.com/Storyyeller/Krakatau -
你把东西留在循环中的堆栈上。
-
为什么要操作行号调试信息?这与您在该声明之前给出的任务描述相矛盾。此外,您应该根据执行转换的代码来展示您实际做了什么。
-
这似乎是您所描述的代码操作的一小部分。没有调用
callAFunctionToDoSthing,没有重定向ar/ar2访问temp,并且没有定义标签l45Ins的代码位置。此外,您没有展示解析原始类和生成新类的方式。 -
我们不能事先说哪个部分与问题相关。如果您怀疑问题是由转换的特定部分引起的,只需尝试剥离其他所有内容并测试问题是否仍然存在。当您拥有重现问题所需的最少代码时发布它,无论它有多大。
标签: java bytecode java-bytecode-asm bytecode-manipulation jvm-bytecode