拓展阅读

开源 Auto generate mock data for java test.(便于 Java 测试自动生成对象信息)

开源 Junit performance rely on junit5 and jdk8+.(java 性能测试框架。性能测试。压测。测试报告生成。)

test fuzz-01-模糊测试(Fuzz Testing)

Soot

重要提示:Soot现已由SootUp接替!

在2022年12月,我们正式发布了SootUp,这是Soot的一个版本,具有完全经过重新设计的、更模块化、可测试、可维护和可用的架构。如果您想要开始一个新的程序分析项目,请查看一下。

Soot现已支持Java 9模块! 尝试并参与Soot的Java 9最新开发。

已经测试并且可用的有:

  • 自动模块(从模块路径中的jar自动创建的模块)
  • 命名模块
  • 爆炸式模块
  • 模块化的jar文件
  • 在Soot的ModuleScene中解析模块
  • Spark

目前尚未实现的有:

  • 匿名模块(混合模块路径和类路径)
  • 多模块的jar文件

什么是Soot?

Soot是一个Java优化框架。

它提供了四种用于分析和转换Java字节码的中间表示:

  1. Baf:一个简化的字节码表示,易于操作。
  2. Jimple:一个适用于优化的带类型的3地址中间表示。
  3. Shimple:Jimple的SSA变体。
  4. Grimp:适用于反编译和代码检查的Jimple的聚合版本。

详细信息请参阅 https://soot-oss.github.io/soot。

如何开始使用Soot?

我们在wiki上提供了一些关于Soot的文档,还有许多关于Soot的教程

有关详细信息,请考虑查阅Soot的JavaDoc和选项文档。

将Soot包含到您的项目中

每次提交到主分支(master)时,都会构建一个Soot发布版本。

您可以通过Maven、Gradle、SBT等工具使用以下坐标将Soot作为依赖项引入项目:

<dependencies>
  <dependency>
    <groupId>org.soot-oss</groupId>
    <artifactId>soot</artifactId>
    <version>4.3.0</version>
  </dependency>
</dependencies>

您还可以获取主分支的旧版本构建。

可以在Maven Central上找到所有版本的构建列表。

每次提交到开发分支(develop)时,都会构建一个Soot SNAPSHOT版本。

您可以通过Maven、Gradle、SBT等工具使用以下坐标将Soot作为依赖项引入项目:

<dependencies>
  <dependency>
    <groupId>org.soot-oss</groupId>
    <artifactId>soot</artifactId>
    <version>4.4.0-SNAPSHOT</version>
  </dependency>
</dependencies>

<repositories>
  <repository>
      <id>sonatype-snapshots</id>
      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
      <releases>
          <enabled>false</enabled>
      </releases>
  </repository>
</repositories>

您还可以获取开发分支的旧版本构建。

可以在Maven Central上找到所有版本的构建列表。

如何获取没有Maven的Soot? 我们推荐使用Maven来使用Soot,您可以直接获取Soot的最新发行构建。您也可以直接获取Soot的最新SNAPSHOT构建。

soot-<RELEASE>-jar-with-dependencies.jar 文件是一个包含所有必需库的全功能文件。

soot-<RELEASE>.jar 文件仅包含Soot,允许您手动选择依赖项,按需加载。如果您不想处理依赖关系,我们建议使用前者。

自行构建Soot

如果您无法使用预构建版本并需要自行构建Soot,请考虑查阅wiki以获取更多详细步骤。

关于Soot源代码

Soot遵循git-flow约定。发布和热修复版本都在主分支(master)中维护。

开发发生在开发分支(develop)中。要获取Soot的最新版本,请查看后者。

如有任何问题,请咨询Soot邮件列表:http://www.sable.mcgill.ca/mailman/listinfo/soot-list/

如何贡献给Soot?

我们欢迎以GitHub拉取请求的形式提交对Soot的任意改进。在设置拉取请求之前,请阅读我们的贡献指南。

请帮助我们改进Soot!

您正在使用Soot并希望在未来帮助我们支持它吗?那么,请通过填写这个小型网络表单来支持我们。

这样,您可以通过两种方式帮助我们:

  1. 通过告诉我们如何改进Soot,您可以直接帮助我们确定新计划功能的优先级。

  2. 通过提供您的姓名和机构,您可以帮助我们展示Soot庞大的用户群体。谢谢!

如何使用Soot的Java 9功能?

如果要在Java 8之后的版本中运行Soot,只需像往常一样运行即可。

如果要使用Java 8执行Soot但分析Java 8之后的项目,或反之,可参考下文。

从源代码使用

要从Java中加载Soot的ModuleScene中的模块:

// 配置Soot的选项,请参考下面的示例配置
Options.v().set_soot_modulepath(modulePath);

// 将模块中的类加载到Soot中
// 这里,getClassUnderModulePath() 期望使用上面所示的Options类设置模块路径
Map<String, List<String>> map = ModulePathSourceLocator.v().getClassUnderModulePath(modulePath);
for (String module : map.keySet()) {
    for (String klass : map.get(module)) {
        logger.info("Loaded Class: " + klass + "\n");
        loadClass(klass, false, module);
        // loadClass() 方法在下面定义
    }
}

// 所有类加载完成后必须调用此方法
Scene.v().loadNecessaryClasses();

public static SootClass loadClass(String name, boolean main, String module) {
     SootClass c = ModuleScene.v().loadClassAndSupport(name, Optional.of(module));
     c.setApplicationClass();
     if (main)
         Scene.v().setMainClass(c);
     return c;
}

ModuleUtil.module_mode() 可以帮助您检查在Soot中是否启用了模块。这是根据是否使用Options类设置了模块路径来完成的。

示例配置:Java 8,Java >= 9 类路径,Java >= 9 模块路径

if (java < 9) { // 当目标基准测试使用Java < 9且因此没有模块时
    Options.v().set_prepend_classpath(true);
    Options.v().set_process_dir(Arrays.asList(applicationClassPath().split(File.pathSeparator)));
    Options.v().set_soot_classpath(sootClassPath());
}

if (java >= 9 && USE_CLASSPATH) { // 当目标基准测试使用Java >= 9且不需要模块支持时
    Options.v().set_soot_classpath("VIRTUAL_FS_FOR_JDK" + File.pathSeparator + sootClassPath());
    Options.v().set_process_dir(Arrays.asList(applicationClassPath().split(File.pathSeparator)));
}

if (java >= 9 && USE_MODULEPATH) { // 当目标基准测试使用Java >= 9且需要模块支持时
    Options.v().set_prepend_classpath(true);
    Options.v().set_soot_modulepath(sootClassPath());
    Options.v().set_process_dir(Arrays.asList(applicationClassPath().split(File.pathSeparator)));
}

在上述示例中,applicationClassPath() 应替换为Soot分析的应用程序类的路径,sootClassPath() 应替换为Soot类路径。

从命令行使用

要使用Java 1.9执行Soot,但分析类路径运行,与以前一样运行:

java -cp soot-trunk.jar soot.Main --process-dir directoryToAnalyse

如果要明确指定类路径,请运行:

java -cp soot-trunk.jar soot.Main -cp VIRTUAL_FS_FOR_JDK --process-dir directoryToAnalyse

VIRTUAL_FS_FOR_JDK 表示Soot应该搜索Java(>9)的虚拟文件系统jrt:/中的类,即使Soot没有在模块模式下执行。

要在Java 1.8中运行Soot并加载模块和类,请运行:

java -cp PATH_TO_JAVA9/jrt-fs.jar:soot-trunk.jar soot.Main -pp -soot-modulepath modules/

请将 PATH_TO_JAVA9 替换为Java 9的本地安装路径。

jrt-fs.jar 是Java 9使用的jrt://文件系统的内置NIO文件系统提供程序,用于替换rt.jar

chat

详细介绍一下 soot

Soot是一个用于分析和转换Java字节码的开源框架。它为静态分析、优化和深入理解Java程序提供了强大的工具。以下是关于Soot的详细介绍:

1. 目标和用途:

  • 静态分析: Soot主要用于进行静态分析,即在程序运行之前分析程序的结构和性质。
  • 优化: Soot可以应用多种优化技术,改善程序的性能和资源利用率。
  • 转换: Soot允许用户对Java字节码进行各种转换,包括插桩(instrumentation)、重构(refactoring)等。

2. 主要特性:

  • 模块化设计: Soot采用模块化的设计,允许用户选择性地使用其功能。这使得它可以灵活地嵌入到各种项目中。
  • 可扩展性: Soot提供了丰富的API,使得开发人员可以轻松地扩展和自定义分析和转换。
  • 支持多种分析和优化: Soot支持诸如活跃变量分析、数据流分析、切片分析等多种分析技术,同时也支持诸如内联、常量折叠等多种优化技术。

3. 主要组件:

  • Front-end(前端): 负责将Java源代码或字节码转换为内部表示形式。
  • Intermediate Representation(中间表示): Soot使用Shimple作为其内部表示,一种高级的SSA(Static Single Assignment)形式。
  • Analysis Packs: 包含各种分析和优化的集合,用户可以选择性地启用这些分析和优化。

4. 使用场景:

  • 研究: 由于其灵活性和可扩展性,Soot在研究领域中经常被用于开发新的静态分析技术和优化算法。
  • 工具开发: Soot被广泛应用于开发与Java字节码相关的工具,如代码检查工具、测试工具等。

5. 工作流程:

  • 加载字节码: Soot首先加载Java字节码,可以是从Java源代码编译而来,也可以是从已有的.class文件中提取。
  • 分析: Soot执行各种分析,例如数据流分析、活跃变量分析等,以理解程序的结构和行为。
  • 优化: 基于分析结果,Soot可以应用各种优化,改进程序的性能。
  • 输出: Soot可以将分析或转换后的结果输出为新的字节码文件或其他形式。

6. 社区和支持:

  • Soot是一个活跃的开源项目,拥有一个积极的社区。用户可以在论坛、邮件列表等地方获取支持和交流经验。

总体而言,Soot是一个功能强大的工具,适用于对Java程序进行深入分析和优化的场景。由于其模块化和可扩展的设计,它在研究和工业界都得到了广泛的应用。

给一个 soot 具体的 java 入门例子

以下是一个简单的使用 Soot 进行静态分析的 Java 入门示例。这个示例使用 Soot 分析一个简单的 Java 类,获取该类的方法和字段信息。

首先,确保你已经下载并设置好 Soot。你可以在 Soot 官方网站 上获取最新版本的 Soot。

然后,创建一个 Java 类(例如 SampleClass.java):

public class SampleClass {
    private int sampleField;

    public SampleClass() {
        sampleField = 42;
    }

    public void sampleMethod(int parameter) {
        System.out.println("Sample Method: " + parameter);
    }

    public static void main(String[] args) {
        SampleClass sampleObj = new SampleClass();
        sampleObj.sampleMethod(10);
    }
}

接下来,创建一个 Java 类(例如 AnalysisExample.java)来使用 Soot 分析 SampleClass

import soot.*;

public class AnalysisExample {
    public static void main(String[] args) {
        String classPath = "path/to/SampleClass.class"; // 替换为 SampleClass.class 的路径

        // 设置 Soot
        Options.v().set_verbose(true);
        Options.v().set_output_format(Options.output_format_jimple);
        Scene.v().setSootClassPath(classPath);

        // 加载类
        SootClass sootClass = Scene.v().forceResolve("SampleClass", SootClass.BODIES);
        sootClass.setApplicationClass();

        // 遍历类的方法
        for (SootMethod method : sootClass.getMethods()) {
            System.out.println("Method: " + method.getName());
        }

        // 遍历类的字段
        for (SootField field : sootClass.getFields()) {
            System.out.println("Field: " + field.getName());
        }
    }
}

确保替换 path/to/SampleClass.classSampleClass.class 的实际路径。

在这个例子中,我们使用 Soot 分析了 SampleClass 中的方法和字段信息,并打印了它们的名称。

运行 AnalysisExample.java,你应该能够看到输出包含了 SampleClass 中的方法和字段信息。

请注意,这只是 Soot 的一个简单用法示例。在实际的静态分析工作中,你可能需要更详细的分析和优化,具体取决于你的需求。

你可以查阅 Soot 的官方文档以获取更多详细信息和功能。

让你深入学习 soot,你会问哪10个问题?为什么?

深入学习 Soot时,你可能会问以下10个问题,这些问题可以帮助你更全面地理解 Soot 的内部机制和功能:

  1. Soot的主要设计目标是什么?
    • 理解 Soot 的设计目标有助于确定其适用的使用场景和优势。
  2. Soot如何处理Java字节码?
    • 了解 Soot 是如何加载、解析和分析 Java 字节码的,以及它采用的中间表示形式。
  3. Soot如何实现静态分析?
    • 深入了解 Soot 的静态分析能力,包括数据流分析、活跃变量分析等。
  4. Soot中的Shimple是什么,为什么使用它?
    • 了解 Shimple 是 Soot 中的一种中间表示形式,以及它相对于其他表示形式的优势。
  5. Soot的优化能力有哪些,如何使用?
    • 掌握 Soot 提供的优化技术,包括内联、常量折叠等,以及如何在分析中应用这些优化。
  6. Soot如何处理Java程序中的异常?
    • 了解 Soot 如何处理异常信息,包括异常的传播和处理路径。
  7. Soot如何与外部工具集成?
    • 了解 Soot 如何与其他工具和框架集成,例如与JUnit结合进行测试生成,以及如何在实际项目中使用 Soot。
  8. Soot的社区活跃度如何?
    • 了解 Soot 的社区活跃程度,包括问题和解决方案的讨论,以及是否有最新的版本发布。
  9. Soot的性能特性是什么?
    • 了解 Soot 的性能,包括分析大型代码库时的效率和资源消耗。
  10. Soot适用于哪些应用场景?
    • 了解 Soot 在哪些领域和场景中表现出色,以及它在静态分析、代码优化等方面的主要应用。

这些问题涵盖了 Soot 的核心原理、设计决策和实际应用,有助于你深入学习和有效使用 Soot 进行静态分析和代码转换。

给出一个 soot 在 静态分析 具体的例子?

静态分析是Soot强大功能之一,它允许您在不实际运行程序的情况下检查和理解代码。

以下是一个简单的Soot静态分析的例子,该例子演示如何使用Soot获取Java代码中方法的签名信息:

import soot.*;
import soot.jimple.*;
import soot.options.Options;

import java.util.Iterator;

public class SootStaticAnalysisExample {

    public static void main(String[] args) {
        // 设置Soot的选项
        String classPath = "path/to/your/classes"; // 替换为实际的类路径
        Options.v().set_soot_classpath(classPath);
        Options.v().set_whole_program(true);
        Options.v().setPhaseOption("jb", "use-original-names:true");

        // 加载类并分析
        String className = "your.package.YourClass"; // 替换为要分析的类的名称
        SootClass sootClass = Scene.v().forceResolve(className, SootClass.SIGNATURES);
        sootClass.setApplicationClass();
        Scene.v().loadNecessaryClasses();

        // 打印方法签名信息
        Iterator<SootMethod> methodIterator = sootClass.getMethods().iterator();
        while (methodIterator.hasNext()) {
            SootMethod method = methodIterator.next();
            System.out.println("Method Signature: " + method.getSignature());
        }
    }
}

请确保替换path/to/your/classesyour.package.YourClass为实际的类路径和类名。

这个简单的例子加载了指定的Java类并打印了该类中每个方法的签名信息。

在实际的静态分析中,您可能会执行更复杂的分析,如数据流分析、控制流分析等,以深入理解程序的结构和行为。

Soot提供了强大的框架,使得进行这些更深入的分析变得可能。

给出一个 soot 在 代码优化 具体的例子?

Soot在代码优化方面的应用非常广泛,它可以进行多种类型的优化,包括常见的控制流优化、数据流优化等。

以下是一个简单的Soot代码优化的例子,展示如何使用Soot进行常量传播:

import soot.*;
import soot.jimple.*;
import soot.options.Options;

public class SootConstantPropagationExample {

    public static void main(String[] args) {
        // 设置Soot的选项
        String classPath = "path/to/your/classes"; // 替换为实际的类路径
        Options.v().set_soot_classpath(classPath);
        Options.v().set_whole_program(true);
        Options.v().setPhaseOption("jb", "use-original-names:true");

        // 加载类并进行常量传播优化
        String className = "your.package.YourClass"; // 替换为要优化的类的名称
        SootClass sootClass = Scene.v().forceResolve(className, SootClass.SIGNATURES);
        sootClass.setApplicationClass();
        Scene.v().loadNecessaryClasses();

        // 进行常量传播优化
        PackManager.v().getPack("jtp").add(new Transform("jtp.myTransform", new BodyTransformer() {
            protected void internalTransform(Body body, String phaseName, Map<String, String> options) {
                for (Unit unit : body.getUnits()) {
                    if (unit instanceof Stmt) {
                        Stmt stmt = (Stmt) unit;
                        if (stmt.containsInvokeExpr()) {
                            InvokeExpr invokeExpr = stmt.getInvokeExpr();
                            if (invokeExpr.getMethod().getName().equals("println")) {
                                // 如果调用的是System.out.println(),将其替换为常量
                                IntConstant constant = IntConstant.v(42); // 替换为您想要的常量值
                                AssignStmt assignStmt = Jimple.v().newAssignStmt(invokeExpr, constant);
                                body.getUnits().insertAfter(assignStmt, stmt);
                                body.getUnits().remove(stmt);
                            }
                        }
                    }
                }
            }
        }));

        // 输出优化后的方法
        for (SootMethod method : sootClass.getMethods()) {
            System.out.println("Optimized Method: " + method.getName());
            System.out.println(method.retrieveActiveBody());
        }
    }
}

请确保替换path/to/your/classesyour.package.YourClass为实际的类路径和类名。

这个例子中,我们将System.out.println()调用替换为一个常量值,实现了简单的常量传播优化。

在实际的代码优化中,您可能会执行更复杂的优化,如内联、循环展开等,以提高程序的性能和效率。Soot为这些优化提供了强大的框架和工具。

参考资料