我们正在开发 mutation testing system based on LLVM .该系统支持使用 GoogleTest 的 C++ 项目,我正在尝试支持 Rust。为此,我们需要完成以下步骤:
- 将语言编译成 LLVM IR。 Rust 支持这一点。
- 在 LLVM IR 中找到测试。
- 运行测试(“受测者”)执行的代码。
挑战在于通过 LLVM IR API 找到单元测试方法。
考虑 the following example .它有4个测试和一个被测试者函数:
pub fn sum(a: i32, b: i32) -> i32 {
return a + b;
}
pub fn just_print() {
println!("I am just_print() function. I just say hello!");
}
#[test]
fn rusttest_foo_sum1() {
assert!(sum(3, 4) == 7);
}
#[test]
fn rusttest_foo_sum2() {
assert!(sum(4, 5) == 9);
}
#[test]
fn rusttest_foo_sum3() {
assert!(sum(5, 6) == 11);
}
#[test]
fn rusttest_foo_sum4() {
assert!(sum(5, 6) == 11);
}
这是 the slightly prettified LLVM IR这是编译此 Rust 代码时产生的。
探索 LLVM IR 一段时间后,可以注意到 Rust/Cargo 通过函数 main
运行测试,该函数调用 test_main_static
函数,该函数被赋予描述数组.每个描述都是一对测试函数名和测试函数指针。 See the @ref.e
at line 47 .
我们的挑战是通过解析这个复杂的结构布局来收集指向这些测试的函数指针,以便稍后我们可以通过 LLVM JIT 为它提供我们积累的函数指针来运行这些函数。
我们将采用的明显的蛮力方法是遍历此结构布局并仔细解析结构并找到测试函数的正确偏移量。这种方法似乎无法跨不同版本的 Rust 或 LLVM IR 移植,这些版本可能会在未来发生变化。
除了默认的手动解析偏移量之外,找到测试函数指针的最简单同时可靠的方法是什么?
这个问题也被cross-posted to the Rust forums .
最佳答案
我made it work通过使用我在问题中概述的蛮力方法。使用 LLVM C++ API,我们:
- 找到指向
test_main_static
的指针> - 在
test_main_static
中找到对@ref.e
的引用> - 枚举
@ref.e
结构,找到测试函数指针
该方法似乎可行,但我们仍然担心它可能无法跨不同版本的 Rust/LLVM 移植。我们接下来的步骤之一是对 rustc --test
生成的 LLVM IR 进行完整性检查。另一个步骤是在真实代码库上尝试这个 RustTestFinder
,看看我们是否有任何问题。
我仍然会感谢 rustc --test
生成的任何有关 LLVM IR 的信息,这些信息可以使事情变得更简单。
关于rust - 如何从 Rust 程序的 LLVM IR 代码中找到用于测试的函数指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42177712/