如何检测Java字节码中的数组大小(FindBugs)

时间:2021-08-28 16:53:31

I'd like to find out about the size of an array being allocated by looking at the bytecode, if that information is known at compile time, of course.

我想通过查看字节码来了解正在分配的数组的大小,当然,如果在编译时知道该信息。

Background: I want to write a FindBugs detector (which looks at the compiled bytecode) and report certain occurences of array allocations. In order to filter out false positives I am not interested in "small" arrays, but only ones whose size is not available at compile time or that are larger than a configurable threshold.

背景:我想编写一个FindBugs检测器(查看编译的字节码)并报告某些阵列分配的发生。为了滤除误报,我对“小”数组不感兴趣,只对编程时大小不可用或大于可配置阈值的数组感兴趣。

As the FindBugs sourcecode is not too heavily documented, I am looking for some pointers on how to get started - maybe there already is a dectector doing something similar that I could look at.

由于FindBugs的源代码没有太多文档记录,我正在寻找一些关于如何开始的指针 - 也许已经有一个dectector做了类似我能看到的东西。

2 个解决方案

#1


This could get kind of tricky. My knowledge is incomplete, but you'll have at least three kinds of instructions to look out for (NEWARRAY, ANEWARRAY and MULTIANEWARRAY). Looking at the previous instruction (or in the case of MULTIANEWARRAY, n previous instructions) gets the size, which even if it was a constant might be loaded with BIPUSH, SIPUSH or LDC (anything else?) depending on the size. As you've noted, if the class is the result of a calculation, you may be tracing instructions back indefinitely.

这可能会有点棘手。我的知识不完整,但你至少要注意三种指令(NEWARRAY,ANEWARRAY和MULTIANEWARRAY)。查看上一条指令(或者在MULTIANEWARRAY的情况下,n先前的指令)获取大小,即使它是一个常量,也可以加载BIPUSH,SIPUSH或LDC(其他任何东西?),具体取决于大小。正如您所指出的,如果该类是计算的结果,您可能会无限期地追溯指令。

If I remember correctly, FindBugs uses the BCEL internally, but I've never dug around in there to see exactly how clever they're being. If either of those teams have appropriate mailing lists, they may prove a better place to ask - they'll probably at least know if someone has been down this road before.

如果我没记错的话,FindBugs会在内部使用BCEL,但我从来没有在那里挖掘过,看看他们究竟有多聪明。如果这些团队中的任何一个拥有适当的邮件列表,他们可能会被证明是一个更好的地方 - 他们可能至少知道某人之前是否曾经走过这条路。

#2


Well, if they are allocated based on a constant, you could check for a constant that was pushed just before the allocation. For example:

好吧,如果基于常量分配它们,您可以检查在分配之前推送的常量。例如:

class ArraySize {
    private static final int smallsize = 10;
    private static final int largesize = 1000;
    public static void main(String[] args) {
        int[] small = new int[smallsize];
        int[] big = new int[largesize];
    }
}

gives the bytecode:

给出字节码:

Compiled from "ArraySize.java"
class ArraySize extends java.lang.Object{
ArraySize();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   bipush  10
   2:   newarray int
   4:   astore_1
   5:   sipush  1000
   8:   newarray int
   10:  astore_2
   11:  return

}

#1


This could get kind of tricky. My knowledge is incomplete, but you'll have at least three kinds of instructions to look out for (NEWARRAY, ANEWARRAY and MULTIANEWARRAY). Looking at the previous instruction (or in the case of MULTIANEWARRAY, n previous instructions) gets the size, which even if it was a constant might be loaded with BIPUSH, SIPUSH or LDC (anything else?) depending on the size. As you've noted, if the class is the result of a calculation, you may be tracing instructions back indefinitely.

这可能会有点棘手。我的知识不完整,但你至少要注意三种指令(NEWARRAY,ANEWARRAY和MULTIANEWARRAY)。查看上一条指令(或者在MULTIANEWARRAY的情况下,n先前的指令)获取大小,即使它是一个常量,也可以加载BIPUSH,SIPUSH或LDC(其他任何东西?),具体取决于大小。正如您所指出的,如果该类是计算的结果,您可能会无限期地追溯指令。

If I remember correctly, FindBugs uses the BCEL internally, but I've never dug around in there to see exactly how clever they're being. If either of those teams have appropriate mailing lists, they may prove a better place to ask - they'll probably at least know if someone has been down this road before.

如果我没记错的话,FindBugs会在内部使用BCEL,但我从来没有在那里挖掘过,看看他们究竟有多聪明。如果这些团队中的任何一个拥有适当的邮件列表,他们可能会被证明是一个更好的地方 - 他们可能至少知道某人之前是否曾经走过这条路。

#2


Well, if they are allocated based on a constant, you could check for a constant that was pushed just before the allocation. For example:

好吧,如果基于常量分配它们,您可以检查在分配之前推送的常量。例如:

class ArraySize {
    private static final int smallsize = 10;
    private static final int largesize = 1000;
    public static void main(String[] args) {
        int[] small = new int[smallsize];
        int[] big = new int[largesize];
    }
}

gives the bytecode:

给出字节码:

Compiled from "ArraySize.java"
class ArraySize extends java.lang.Object{
ArraySize();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   bipush  10
   2:   newarray int
   4:   astore_1
   5:   sipush  1000
   8:   newarray int
   10:  astore_2
   11:  return

}