20 个版本

0.7.2 2023年10月27日
0.7.1 2021年10月21日
0.7.0 2021年8月26日
0.6.4 2021年4月23日
0.1.1 2019年11月26日

#18 in 模拟器

Download history 24/week @ 2024-04-01 18/week @ 2024-05-06 2/week @ 2024-05-20 5/week @ 2024-06-10

141 每月下载
haybale-pitchfork 中使用

MIT 许可证

705KB
12K SLoC

haybale: 用 Rust 编写的 LLVM IR 符号执行引擎

crates.io License

haybale 是一个用 Rust 编写的通用符号执行引擎。它操作于 LLVM IR,这使得它可以分析用 C/C++、Rust、Swift 或任何其他编译为 LLVM IR 的语言编写的程序。因此,它可以与 KLEE 相比,因为它们有相似的目标,除了 haybale 是用 Rust 编写的,并做出了不同的设计决策。尽管如此,haybale 并不声称在功能上与 KLEE 相等。

好吧,那么符号执行引擎是什么?

符号执行引擎是一种推理方式——严格且数学化——关于函数或程序的行为。它可以对函数的所有可能的输入进行推理,而无需逐个硬暴力。例如,像 haybale 这样的符号执行引擎可以回答以下问题:

  • 有哪些输入会导致(某个函数)返回 0?它们是什么?
  • 这个循环是否能恰好执行 17 次?
  • 这个指针是否可能为 NULL?

符号执行引擎通过将程序或函数中的每个变量转换为依赖于函数或程序输入的数学表达式来回答这些问题。然后,它们使用 SMT 求解器来回答关于这些表达式的问题,例如上述问题。

入门指南

1. 安装

haybalecrates.io 上,所以您只需将其添加到您的 Cargo.toml 中的依赖项,选择与您想要的 LLVM 版本对应的特性

[dependencies]
haybale = { version = "0.7.2", features = ["llvm-14"] }

目前支持的 LLVM 版本有 llvm-9llvm-10llvm-11llvm-12llvm-13llvm-14

haybale 依赖于(间接地)LLVM 和 Boolector 库。

  • LLVM 必须在您的系统上可用,版本应与所选功能匹配。(例如,如果您选择了 llvm-14 功能,则您的系统上必须有 LLVM 14。)有关安装 LLVM 的详细信息以及确保 Cargo 可以找到它的说明,请参阅 llvm-sys README。
  • 对于 Boolector,您有两个选项
    • 您可以在系统上编译并安装 Boolector 3.2.1 作为共享库。(确保将其配置为共享库,例如,使用 ./configure.sh --shared,然后使用 make install 安装。)
    • 或者,您可以启用 haybale 功能 vendor-boolector。使用此选项,Cargo 将自动下载并构建 Boolector 并将其静态链接。例如,
      [dependencies]
      haybale = { version = "0.7.2", features = ["llvm-14", "vendor-boolector"] }
      
      此选项可能仅在 Linux 和 macOS 上工作,并且需要您的系统上有标准构建工具 -- 例如,对于基于 Debian 的发行版,build-essentialcmakecurlgit

2. 获取要分析的位代码

由于 haybale 在 LLVM 位代码上运行,您需要一些位代码才能开始。如果您想要分析的程序或函数是用 C 编写的,您可以使用 clang-c-emit-llvm 标志生成 LLVM 位代码(*.bc 文件)

clang -c -emit-llvm source.c -o source.bc

出于调试目的,您可能还需要 LLVM 文本格式(*.ll)文件,您可以使用 clang-S-emit-llvm 标志生成

clang -S -emit-llvm source.c -o source.ll

如果您想要分析的程序或函数是用 Rust 编写的,您同样可以使用 rustc--emit=llvm-bc--emit=llvm-ir 标志。

请注意,为了使 haybale 能够在错误消息和回溯中打印源位置信息(例如,源文件名和行号),LLVM 位代码需要包含调试信息。您可以通过在生成位代码时将 -g 标志传递给 clangclang++rustc 来确保包含调试信息。

3. 创建项目

haybaleProject 包含目前正在分析的代码,这可能是一个或多个 LLVM 模块。要开始,只需从单个位代码文件创建一个 Project 即可

let project = Project::from_bc_path("/path/to/file.bc")?;

有关创建 Project 的更多方法,包括分析整个库,请参阅 Project 文档

4. 使用内置分析

haybale 目前包含两个简单的内置分析:一个get_possible_return_values_of_func(),它描述了函数对于任何输入可能返回的所有值,另一个是find_zero_of_func(),它找到一个函数的输入集合,使得函数返回 0。这些分析之所以提供,一方面是因为它们可能有用,另一方面是因为它们展示了如何使用 haybale

作为一个入门示例,假设 foo 是以下 C 函数

int foo(int a, int b) {
    if (a > b) {
        return (a-1) * (b-1);
    } else {
        return (a + b) % 3 + 10;
    }
}

我们可以使用 find_zero_of_func() 来找到使得 foo 返回 0 的输入

match find_zero_of_func("foo", &project, Config::default(), None) {
    Ok(None) => println!("foo can never return 0"),
    Ok(Some(inputs)) => println!("Inputs for which foo returns 0: {:?}", inputs),
    Err(e) => panic!("{}", e),  // use the pretty Display impl for errors
}

编写自定义分析

haybale 可以做的不仅仅是描述可能的功能返回值和找到功能零点。在本节中,我们将通过不使用内置的 find_zero_of_func() 来找到上述 foo 函数的零点。这将为如何使用 haybale 编写自定义分析提供示例。

ExecutionManager

所有分析都将使用一个 ExecutionManager 来控制符号执行的进度。在下面的代码片段中,我们调用 symex_function() 来创建一个 ExecutionManager,该管理器将分析函数 foo - 它将从函数的顶部开始,并在函数返回时结束。在此期间,它还将根据 Config 设置分析 foo 调用的任何函数。

let mut em = symex_function("foo", &project, Config::<DefaultBackend>::default(), None);

这里不仅需要指定与调用 find_zero_of_func() 时相同的默认 haybale 配置,还需要指定我们想要使用的“后端”。对于大多数目的而言,DefaultBackend 应该是足够的。

Paths

ExecutionManager 类似于函数 foo 中的 路径 迭代器。每条路径都是可能导致函数返回某些值的控制流决策的可能序列(例如,在每次 if 语句中我们选择哪个方向)。在这个示例中,函数 foo 有两条路径,一条是“true”分支,另一条是“false”分支。

让我们检查通过函数的第一条路径

let result = em.next().expect("Expected at least one path");

在常见情况下,result 包含此路径上的函数返回值,作为 Boolector BV(位向量)封装在 ReturnValue 枚举中。由于我们知道 foo 不是一个空类型函数(并且不会抛出异常或中止),我们可以简单地解包 ReturnValue 以获取 BV

let retval = match result {
    Ok(ReturnValue::Return(r)) => r,
    Ok(ReturnValue::ReturnVoid) => panic!("Function shouldn't return void"),
    Ok(ReturnValue::Throw(_)) => panic!("Function shouldn't throw an exception"),
    Ok(ReturnValue::Abort) => panic!("Function shouldn't panic or exit()"),
    ...

result 也可以是一个 Err,描述了在处理路径时遇到的 Error。在这种情况下,我们可以忽略错误并继续调用 next() 来尝试找到没有错误的路径。或者,我们可以这样获取有关错误的信息:

    ...
    Err(e) => panic!("{}", em.state().full_error_message_with_context(e)),
};

这将从程序 State 中获取错误信息,我们将在下一节讨论。但在本教程的其余部分,我们将假设我们得到了 Ok 的结果,此时 retval 是表示第一个路径上函数返回值的 BV

状态

对于每条路径,ExecutionManager 不仅提供路径的最终结果(要么是 ReturnValue,要么是 Error),还提供该路径末尾的最终程序 State。我们可以使用 state() 获取对 State 的不可变访问,或者使用 mut_state() 获取可变访问。

let state = em.mut_state();  // the final program state along this path

要测试在这个 Stateretval 是否可以等于 0,我们可以使用 state.bvs_can_be_equal()

let zero = state.zero(32);  // The 32-bit constant 0
if state.bvs_can_be_equal(&retval, &zero)? {
    println!("retval can be 0!");
}

获取变量的解

如果 retval 可以等于 0,让我们找出哪些函数参数的值会导致这种情况。首先,我们将向 State 添加一个约束,要求返回值必须是 0

retval._eq(&zero).assert();

然后我们将根据这个约束请求每个参数的解

// Get a possible solution for the first parameter.
// In this case, from looking at the text-format LLVM IR, we know the variable
// we're looking for is variable #0 in the function "foo".
let a = state.get_a_solution_for_irname(&String::from("foo"), Name::from(0))?
    .expect("Expected there to be a solution")
    .as_u64()
    .expect("Expected solution to fit in 64 bits");

// Likewise the second parameter, which is variable #1 in "foo"
let b = state.get_a_solution_for_irname(&String::from("foo"), Name::from(1))?
    .expect("Expected there to be a solution")
    .as_u64()
    .expect("Expected solution to fit in 64 bits");

println!("Parameter values for which foo returns 0: a = {}, b = {}", a, b);

或者,我们也可以像这样从 ExecutionManager 获取参数的 BV

let a_bv = em.param_bvs()[0].clone();
let b_bv = em.param_bvs()[1].clone();

let a = em.state().get_a_solution_for_bv(&a_bv)?
    .expect("Expected there to be a solution")
    .as_u64()
    .expect("Expected solution to fit in 64 bits");

let b = em.state().get_a_solution_for_bv(&b_bv)?
    .expect("Expected there to be a solution")
    .as_u64()
    .expect("Expected solution to fit in 64 bits");

println!("Parameter values for which foo returns 0: a = {}, b = {}", a, b);

文档

有关 haybale 的完整文档可以在 docs.rs 上找到,或者当然,您可以使用 cargo doc --open 生成本地文档。

兼容性

目前,haybale 的官方 crates.io 版本(0.7.0 及以后)依赖于 Boolector 3.2.1 和 LLVM 9、10、11、12、13 或 14,通过功能标志 llvm-9llvm-14 选择。截至本文写作时,选择 LLVM 版本对 haybale 的功能或接口几乎没有影响;唯一的区别是能够分析使用较新 LLVM 生成的基本代码。(并且 LLVM 10+ 版本可以处理 AtomicRMW 指令;参见 #12。)

对于LLVM 8,您可以尝试使用本仓库的llvm-8分支。这个分支不再维护,其功能和haybale 0.2.1大致相同。它可能满足您的需求;或者,您可以升级到LLVM 9或更高版本以及最新的haybale

LLVM 7及以下版本不受支持。

haybale在稳定的Rust上运行,需要Rust 1.45或更高版本。

底层

haybale使用Rust的llvm-ir crate和Boolector SMT求解器(通过Rust的boolector crate)构建。

变更日志

版本 0.7.2(2023年10月26日)

  • 支持通过llvm-14功能使用LLVM 14
  • 修复/改进了对一些内建的兼容性

版本 0.7.1(2021年10月21日)

  • 通过llvm-13功能支持LLVM 13
  • haybale现在需要Rust 1.45+(之前为1.43或1.44)

版本 0.7.0(2021年8月26日)

  • 通过llvm-12功能支持LLVM 12
  • 新增了Cargo功能以集成Boolector:在haybale构建过程中自动下载、构建和静态链接Boolector。请参阅README中的“安装”部分。
  • symex_function()现在接受一个额外的参数params。您可以使用此参数指定函数参数的约束,甚至指定特定的硬编码值。或者,您可以只传递None并得到之前的haybale行为,将所有参数视为完全未加约束。
  • find_zero_of_func()get_possible_return_values_of_func()同样现在接受一个params参数以指定函数参数的约束。
  • State有一个新的公共字段proj,提供对Project的访问。
  • 函数钩子不再显式地接受Project参数。相反,您可以通过State对象的proj字段访问Project
  • ExecutionManager有一个新的公共方法.func(),它提供了对顶层Function的访问。
  • State有一个新的公共方法get_path_length(),也作为顶层函数get_path_length()可用。
  • llvm-ir依赖更新到0.8.0,这导致haybale API的部分发生了一些小的破坏性更改,其中暴露了llvm-ir类型。

版本 0.6.4 (2021年4月22日)

  • 修复了使用 Rust 1.51+ 构建的问题 (#16)。(haybale 的最低 Rust 版本保持不变:LLVM 9 或 10 用户为 1.43+,LLVM 11 用户为 1.44+)。

版本 0.6.3 (2020年10月26日)

  • 修复了在 docs.rs 上构建文档的问题 (#13)

版本 0.6.2 (2020年10月20日)

  • 通过 llvm-11 功能支持 LLVM 11
  • get_possible_return_values_of_func() 现在正确处理 void 函数 (#10)
  • 支持 LLVM atomicrmw 指令(仅限 LLVM 10+)(#12)
  • 支持 LLVM freeze 指令(仅存在于 LLVM 10+)
  • 内置了对更多与 panic 处理相关的 Rust 标准库函数的支持
  • State 有一个新的公共方法 get_bv_by_irname()
  • 由于 llvm-ir 的要求,LLVM 11 用户需要 Rust 1.44+,而 LLVM 9 或 10 用户仍需 Rust 1.43+。

版本 0.6.1 (2020年9月17日)

  • 现在 StateProject 都有一个方法 size_in_bits(),该方法以位为单位获取任何 Type 的大小,考虑了 Project 的指针大小和结构定义。这是为了取代 state.size()state.size_opaque_aware(),这两个方法现在已弃用,并将从 haybale 0.7.0 中移除。同样,state.fp_size() 已弃用并重命名为 state.fp_size_in_bits()
    • 注意:这些弃用方法实际上已在 0.7.1 中移除。

版本 0.6.0 (2020年9月1日)

  • haybale 现在同时支持 LLVM 9 和 LLVM 10,使用相同的分支和相同的 crates.io 发布。当使用 haybale 时,您必须选择 llvm-9llvm-10 功能。
  • 已更新 llvm-ir 依赖项至 0.7.1(从 0.6.0),其中包括运行时和内存使用性能改进,尤其是对于大位代码文件。这也涉及对 haybale API 的部分破坏性更改。
  • 由于 llvm-ir 0.7.1 的要求,haybale 现在需要 Rust 1.43+(以前为 1.40+)。

版本 0.5.1 (2020年8月31日)

  • 修复了关于零元素数组的问题 #9(尤其是在分析 Rust 代码时可能出现)
  • 内置对 llvm.ctlzllvm.cttz 内置函数的支持

版本 0.5.0(2020年7月29日)

兼容性

  • haybale 默认现在依赖于 LLVM 10(由 LLVM 9 升级)。LLVM 9 仍然在单独的分支上得到支持;请参阅上面的“兼容性”。
  • 更新 boolector 依赖项到 crate 版本 0.4.0,该版本需要 Boolector 版本 3.2.1(由 3.1.0 升级)。

影响公共 API 的重命名

  • SimpleMemoryBackend 重命名为 DefaultBackend 并将其设置为默认。将 BtorBackend 重命名为 CellMemoryBackend,并将 memory 模块重命名为 cell_memory
  • 移除 layout 模块。其函数现在作为 State 的方法提供。此外,许多这些函数现在返回 u32 而不是 usize

32 位目标及相关更改

  • 使用 DefaultBackendhaybale 现在支持为 32 位目标编译的 LLVM 位码(之前仅支持 64 位目标)。
  • new_uninitialized()new_zero_initialized() 方法上,simple_memory::Memorycell_memory::Memory 现在将接受一个额外的参数,表示指针大小。
  • Project 新增一个公共方法 pointer_size_bits()

其他

  • 内置对 llvm.expect 内置函数的支持,以及内置对具有向量操作数的 llvm.bswap 内置函数的支持(之前仅支持标量操作数)
  • solver_utils::PossibleSolutions 有新的构造函数 empty()exactly_one()exactly_two()(用于测试),并且还实现了 FromIterator,允许您将迭代器收集到其中
  • 修复了 solver_utils 模块中 {min,max}_possible_solution_for_bv_as_binary_str() 函数的 bug

版本 0.4.0(2020年3月31日)

新功能

  • 支持 LLVM cmpxchg 指令
  • 支持指令回调 - 请参阅 Config.callbacks。这允许您根据即将处理的指令采取任意操作。

配置

  • Config.null_detection 已重命名为 Config.null_pointer_checking,并且其类型已更改,以允许更多的选项。
  • Config::new() 现在不再接受参数。它与 Config::default() 相同,只是它不包含函数钩子。

其他实用函数/方法

  • 现在 hook_utils 模块包含两个新的函数 memset_bvmemcpy_bv
  • layout::size_opaque_aware 现在返回一个 Option 而不是引发恐慌。
  • Location 上的 to_string_* 方法现在是公共的,而不是仅在crate内部,这使用户能够更多地控制 String 的表示。

错误处理

  • Error 有三个新的变体 UnreachableInstructionFailedToResolveFunctionPointerHookReturnValueMismatch。所有这些以前都被报告为 Error::OtherError,但现在有专门的变体。
  • Error::LoopBoundExceeded 现在还包括超过循环界限的值。

其他注意事项

  • haybale 现在不再选择 log crate 的功能。这允许下游用户选择这些功能或不选择,特别是允许用户在发布构建中启用调试日志。

版本 0.3.2(2020 年 2 月 28 日)

  • 新选项 Config.max_callstack_depth 允许您限制分析时的调用栈深度 - 自动忽略会超过该调用栈深度的 LLVM 函数调用。此设置的默认值为无限制,与 haybale 的先前行为一致。
  • 新选项 Config.max_memcpy_length 允许您限制 memcpymemsetmemmove 操作的最大大小。此设置的默认值为无限制,与 haybale 的先前行为一致。
  • 新方法 FunctionHooks::add_default_hook() 允许您提供一个“默认钩子”,当没有找到其他定义或钩子时,将使用该钩子。如果没有提供默认钩子,这将导致 FunctionNotFound 错误,就像以前一样。
  • 分析函数指针调用时的性能改进。
  • 改进了一些错误消息。

版本 0.3.1(2020 年 2 月 5 日)

  • 修复 README 和文档中的一些损坏链接。没有功能上的更改。

版本 0.3.0(2020 年 2 月 5 日)

求解器超时

  • 新设置 Config.solver_query_timeout 控制了 haybale 在返回 Error::SolverError 之前对单个求解器查询的最大时间。此设置默认为 300 秒(5 分钟)。该设置也可以完全禁用,这将导致 haybale(求解器查询无时间限制)的先前版本的行为。

错误处理

  • ExecutionManager.next() 返回的错误现在是 haybale::Error,而不是 String,这使得调用者能够更容易地以不同的方式处理不同类型的错误。要获取 Error 的字符串表示,请使用 .to_string(),它会提供简短描述,而 State.full_error_message_with_context() 提供完整描述,该描述之前由 ExecutionManager.next() 返回。相应的 README 文件中的使用示例也已更新。
  • 顶层函数 find_zero_of_func() 现在返回一个 Result,错误类型为 String
  • 新设置 Config.squash_unsats 控制是否将 Error::Unsat 静默地压缩(默认行为,以及 haybale 的先前版本的行为),或返回给用户。有关更多详细信息,请参阅该设置的文档。

日志记录、错误消息、回溯等

  • haybale 现在在错误消息和回溯中打印源位置信息(例如,源文件名和行号),当可用时。同样,HAYBALE_DUMP_PATH 环境变量现在有 LLVMSRCBOTH 选项。有关所有这些的更多详细信息,请参阅 Config.print_source_info
  • 您现在也可以在错误消息、回溯、路径转储和日志消息中禁用打印与 LLVM 位置信息一起的 LLVM 模块名称。有关更多详细信息,请参阅 Config.print_module_name
  • haybale 现在将默认自动检测是否适用于 Project 的 C++ 或 Rust demangling,除非在 Config.demangling 中选择不同的设置。
  • 表示日志消息、HAYBALE_DUMP_VARS 转储中等中 BV 值的数值常量现在都以十六进制打印(以前是二进制,或二进制和十六进制的混合)。

函数钩子和内联函数

  • 内置对 LLVM 加载溢出内联函数的支持。
  • 内置对 LLVM 满足算术内联函数的支持。
  • 内置对 llvm.assume 内置函数的支持,相关设置请参考 Config.trust_llvm_assumes
  • 内置对 llvm.bswap 内置函数的支持,参数大小为 48 或 64 位(之前仅支持 16 或 32 位)。
  • 为一些总是会导致 panic 的 Rust 标准库函数提供了默认的钩子,例如 core::result::unwrap_failed()
  • 新模块 hook_utils 包含了由相应的内置钩子使用的 memsetmemcpy 的实现。现在这些实现对公共领域开放,可供其他函数的自定义钩子使用。

数据结构和特性更改

  • LocationPathEntry 结构体已被重构,以便在可用时包含源位置信息,能够指示基本块终止符(除了正常指令外),并支持一些内部重构。
  • backend::BV 特性新增了一个必需方法,get_solver(),它返回适当类型的 SolverRef。(这与 backend::Memory 特性上的相同方法类似。)
  • backend::BV 上现在提供了饱和算术方法(有符号和无符号加法和减法),默认实现基于其他特性方法。这意味着,一旦实现了所需的特性方法,这些方法就“免费提供”。
  • zero_extend_to_bits()sign_extend_to_bits() 现在作为 backend::BV 的特性方法提供,默认实现基于其他特性方法。之前它们是 haybale 中的私有实用函数。
  • 许多其他结构体都进行了小的更改和改进,包括一些小的破坏性更改。

兼容性

  • boolector 依赖更新到版本 0.3.0,该版本需要 Boolector 版本 3.1.0(从 3.0.0 升级)。
  • haybale 的此版本现在需要 Rust 1.40+,高于之前版本 haybale 的 1.36+。

版本 0.2.1(2020 年 1 月 15 日)

  • 新增 HAYBALE_DUMP_PATHHAYBALE_DUMP_VARS 环境变量选项
    • HAYBALE_DUMP_PATH:如果设置为 1,则在出错时,haybale 将打印错误路径的描述:从函数顶部到错误位置的每个 LLVM 基本块,按顺序。
    • HAYBALE_DUMP_VARS:如果设置为1,则在出错时,haybale将打印出包含错误的功能中每个变量的最新赋值。
  • 新增设置 Config.demangling,允许您将错误消息和回溯中的函数名应用C++或Rust去混淆。
  • 支持挂钩内联汇编调用,继承自llvm-ir的一些限制(见FunctionHooks::add_inline_asm_hook()的注释)
  • 内置支持(最常见的)llvm.bswap内省
  • 其他细微调整 - 例如,将一个panic降级为警告

版本 0.2.0(2020年1月8日)

  • 支持LLVM extractvalueinsertvalue指令
  • 支持LLVM invokeresumelandingpad指令,以及C++的throw/catch。还提供了一些相关C++ ABI函数的内置钩子,如__cxa_throw()。这项支持并不完美,特别是在匹配catch块和异常方面:haybale可能会探索一些实际上并不有效的路径。但所有实际有效的路径都应被正确找到和探索。
  • 由于函数不仅可以使用LLVM call指令调用,还可以使用LLVM invoke指令调用,因此函数钩子现在接收一个可能代表callinvoke指令的&dyn IsCall对象。
  • haybale现在使用LLVM 9而不是LLVM 8。请参阅README中的“兼容性”部分。
  • 针对包含C++和/或Rust代码的Project的改进
  • ReturnValue 枚举现在有额外的选项 Throw,表示未捕获的异常,以及 Abort,表示程序中止(例如 Rust panic,或调用 C 的 exit())。
  • 相关地,haybale 现在为 C 的 exit() 函数和 Rust panic(以及一些其他 LLVM 内置函数)提供了内置钩子。
  • haybale 还现在包含了一个内置的 generic_stub_hookabort_hook,您可以将它们作为钩子提供给任何您想忽略实现或始终中止的函数。请参阅 function_hooks 模块的文档。
  • Config.initial_mem_watchpoints 现在是一个对 HashMap 的哈希集合,而不是对对的哈希集合。

版本 0.1.3(2020 年 1 月 1 日)

  • 内存监视点:指定一组内存地址范围,并为读取或写入该范围内任何数据的任何内存操作获取日志消息。请参阅 State::add_mem_watchpoint()
  • State 上添加了方便的方法来构建具有常量值的 BV(而不是必须使用 BV 的相应方法并传递 state.solver):bv_from_i32()bv_from_u32()bv_from_i64()bv_from_u64()bv_from_bool()zero()one()ones()
  • 一些内部代码重构,为 0.2.0 功能做准备

版本 0.1.2(2019 年 12 月 18 日)

  • 新增方法 Project::get_inner_struct_type_from_named(),它通过在整个 Project 中搜索给定结构的定义来处理不透明结构类型
  • 支持大小为 1-7 位的内存读取(特别是 LLVM i1 的读取)
  • 性能优化:在 State 初始化期间,全局变量现在仅分配,而不会在首次使用之前进行初始化(惰性初始化)。这使 SMT 求解器需要考虑的内存写入更少,特别是对于包含许多实际上在给定分析中不会使用的全局变量的大型 Project,特别有帮助。
  • 小的错误修复和改进的错误信息

版本 0.1.1(2019 年 11 月 26 日)

仅更改 README 中的文本;没有功能更改。

版本 0.1.0(2019 年 11 月 25 日)

首次发布!

依赖关系

约 6.5MB
约 148K SLoC