java - 我们如何解释静态代码分析中的异常抛出?

标签 java decompiler

我编写了一个实用程序来为 java 方法创建 CFG(控制流图),其节点是基本 block 而不是指令。

我无法将异常抛出视为 CFG 中的边缘。原因是:

  1. try block 中的每条指令都可能引发异常/错误,这些异常/错误可以由任何嵌套的 try-catch block 处理。如果我们将异常抛出视为边缘,则处理路径的数量会急剧增加,CFG 中的节点数量也会急剧增加。
  2. 在决定哪些跳转是可能的之前,我们需要了解异常的继承层次结构。

静态代码分析器如何解决这个问题?

我卡在这一步了。如果我必须继续,我应该怎么做?

编辑:在我的例子中,我可以限制对那些可以指定在何处和哪些异常被抛出的用例的支持。这解决了我的第二个问题。我仍然想知道通用静态代码分析器如何管理它。

最佳答案

这是我在 Krakatau decompiler 中处理问题的方式:

We need to know the inheritance hierarchy for exceptions before we can decide what jumps are possible.

Krakatau 要求任何引用类的类定义都可用,因此它知道继承层次结构。但是,如果我重新来过,我不会这样做。需要类定义使得用户难以操作反编译器,因为查找和添加依赖项是一个巨大的痛苦。如果您认为分析不太精确,那么您实际上并不需要这个。您可以改为假设所有异常都可以到达所有处理程序。在实践中,我预计它会导致几乎相同的结果。

Every instruction in try block can potentially throw exceptions / errors which can be handled by any of the nesting try-catch blocks. If we consider exception throws as edges, the number of paths to process increases drastically, and so will the number of nodes in CFG.

Krakatau 确实在 CFG 中包含异常作为边,这会导致您发现的问题。为了减少边数,我假装只有某些指令可以抛出(方法调用、数组访问、除法等)。这在技术上是不正确的,但它对现实世界的代码做了正确的事情。我从来没有见过任何真正关心从链接错误、Thread.Stop 或类似错误中抛出的异常的东西。不过,我后来确实添加了一个选项来禁用此行为。

无论如何,这对于大多数代码来说已经足够好了,但有时会导致性能问题。特别是,具有大量字段访问或方法调用的非常大的方法会导致巨大的 CFG,从而使反编译非常缓慢。我尝试了一些技巧来优化它,但最终,解决方案是从基本 block 转移到扩展基本 block 。

Extended Basic Blocks 与 Basic Blocks 类似,除了异常边缘是半隐式表示的,从而导致 CFG 小得多。 EBB 由直线代码组成,除了异常边缘外,中间没有入口点或导出点, block 中的每条指令都由同一组异常处理程序覆盖。这样一来,就不是每条指令都有一个异常边缘,而是每个 block 都有一个异常边缘,从而使事情变得更加高效。

即使是具有数千个方法调用的 Java 方法通常也只有几个 try/catch,因此只有几个 EBB。

关于java - 我们如何解释静态代码分析中的异常抛出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44907244/

相关文章:

actionscript-3 - 保护 Flash AS3 代码 + 与服务器的安全通信

java - 如何访问具有完整文件路径的目录?

java - 使用 jcraft.jsch 更改目录时文件夹不存在

java - Grails和Spring Security如何在 Controller 中获取复合ID?

java - 扩展 log4j/slf4j 记录器

java - 通过 Mapreduce 压缩解压缩 Hdfs 文件时附加制表符分隔列

编译器 C 去 Brainfuck(骚扰教授)?

c# - 反编译大型代码库时的 CallSite <>p__site

c - 反编译后的汇编代码