#mutation #testing #testing-tools #wasi #run-wasm

app wasmut

WebAssembly/WASI模块的突变测试工具

1 个不稳定版本

0.6.0 2023年2月4日
0.1.0 2021年12月1日

#686 in WebAssembly

MIT 许可证

220KB
5.5K SLoC

wasmut

License: MIT CI Coverage Status

wasmut 是一个针对WebAssembly WASI 模块的突变测试工具。

目录

安装

目前,wasmut 正式支持Linux和Windows。macOS也应大部分工作,但我无法保证任何事情,因为我没有访问Mac。

预构建的二进制文件

对于Linux和Windows,可以在本仓库的发布页面找到针对 amd64 架构的预构建二进制文件。

使用Cargo安装

wasmut是用Rust实现的,因此您需要Rust工具链来编译该项目。最低支持的Rust版本(MSRV)是1.67。

要从crates.io安装最新的wasmut版本,请运行以下命令

> cargo install wasmut 

这将默认将 wasmut 安装到 $HOME/.cargo/bin。请确保此路径包含在我们的 $PATH 变量中。

开发

如果您想修改 wasmut,只需检出仓库。请确保包含 testdata 子模块。

> git clone --recursive https://github.com/lwagner94/wasmut

一旦克隆了仓库,您可以使用 test 命令运行测试套件。

cargo test

您可能希望以发布构建运行 wasmut。在开发构建中,运行突变需要更多时间。

cargo run --release -- mutate testdata/simple_go/test.wasm -C

您可以使用 coverage.sh 脚本来生成测试覆盖率报告。请确保已安装 grcov 和Rust编译器的夜间版本。

./coverage.sh

快速入门

安装后,您可以使用 wasmut。首先,您可以尝试 testdata 文件夹中的示例。如果您想用自己的模块使用 wasmut,请确保查看 WebAssembly模块要求 章节。

如果您不带任何标志运行 mutate 命令,wasmut 将尝试在当前目录中加载一个名为 wasmut.toml 的文件,如果找不到它,将回退到默认选项。

> # Run wasmut using default options (no filtering, all operators)
> wasmut mutate testdata/simple_add/test.wasm
[INFO ] No configuration file found or specified, using default config
[INFO ] Using 8 workers
[INFO ] Generated 37 mutations
...

使用 -C/-c 标志,您可以指示 wasmut 从不同的路径加载配置文件。-C 标志将尝试从与模块相同的目录加载 wasmut.toml,而 - 允许您提供配置文件的完整路径。

> wasmut mutate testdata/simple_add/test.wasm -C
[INFO ] Loading configuration file from module directory: "testdata/simple_add/wasmut.toml"
[INFO ] Using 8 workers
[INFO ] Generated 1 mutations
[INFO ] Original module executed in 40 cycles
[INFO ] Setting timeout to 80 cycles
/home/lukas/Repos/wasmut/testdata/simple_add/simple_add.c:3:14: 
KILLED: binop_add_to_sub: Replaced I32Add with I32Sub
    return a + b;
              ^

ALIVE           0
TIMEOUT         0
ERROR           0
KILLED          1
Mutation score  100%

默认情况下,wasmut 将将结果打印到控制台 - 如上所示。如果您添加 --report html 选项,wasmut 将在 wasmut-report 文件夹中创建一个 HTML 报告。

> wasmut mutate testdata/simple_go/test.wasm -C --report html
[INFO ] Loading configuration file from module directory: "testdata/simple_go/wasmut.toml"
[INFO ] Using 8 workers
...

命令行界面

帮助

显示帮助菜单

list-files

List all files of the binary.

If a config is provided, this command will also show whether the file is allowed to be mutated. By
default, wasmut will try to load a wasmut.toml file from the current directory

USAGE:
    wasmut list-files [OPTIONS] <WASMFILE>

ARGS:
    <WASMFILE>
            Path to the wasm module

OPTIONS:
    -c, --config <CONFIG>
            Load wasmut.toml configuration file from the provided path

    -C, --config-samedir
            Attempt to load wasmut.toml from the same directory as the wasm module

    -h, --help
            Print help information

    -V, --version
            Print version information

list-functions

List all functions of the binary.

If a config is provided, this command will also show whether the function is allowed to be mutated.
By default, wasmut will try to load a wasmut.toml file from the current directory

USAGE:
    wasmut list-functions [OPTIONS] <WASMFILE>

ARGS:
    <WASMFILE>
            Path to the wasm module

OPTIONS:
    -c, --config <CONFIG>
            Load wasmut.toml configuration file from the provided path

    -C, --config-samedir
            Attempt to load wasmut.toml from the same directory as the wasm module

    -h, --help
            Print help information

    -V, --version
            Print version information

list-operators

List all available mutation operators.

If a config is provided, this command will also show whether the operator is enabled or not. By
default, wasmut will try to load a wasmut.toml file from the current directory

USAGE:
    wasmut list-operators [OPTIONS] [WASMFILE]

ARGS:
    <WASMFILE>
            Path to the wasm module

OPTIONS:
    -c, --config <CONFIG>
            Load wasmut.toml configuration file from the provided path

    -C, --config-samedir
            Attempt to load wasmut.toml from the same directory as the wasm module

    -h, --help
            Print help information

    -V, --version
            Print version information

mutate

Generate and run mutants.

Given a (possibly default) configuration, wasmut will attempt to discover mutants and subsequently
execute them. After that, a report will be generated

USAGE:
    wasmut mutate [OPTIONS] <WASMFILE>

ARGS:
    <WASMFILE>
            Path to the wasm module

OPTIONS:
    -c, --config <CONFIG>
            Load wasmut.toml configuration file from the provided path

    -C, --config-samedir
            Attempt to load wasmut.toml from the same directory as the wasm module

    -h, --help
            Print help information

    -o, --output <OUTPUT>
            Output directory for reports
            
            [default: wasmut-report]

    -r, --report <REPORT>
            Report output format
            
            [default: console]
            [possible values: console, html]

    -t, --threads <THREADS>
            Number of threads to use when executing mutants

    -V, --version
            Print version information

new-config

Create new configuration file

USAGE:
    wasmut new-config [PATH]

ARGS:
    <PATH>    Path to the new configuration file

OPTIONS:
    -h, --help       Print help information
    -V, --version    Print version information

run

Run module without any mutations

USAGE:
    wasmut run [OPTIONS] <WASMFILE>

ARGS:
    <WASMFILE>    Path to the wasm module

OPTIONS:
    -c, --config <CONFIG>    Load wasmut.toml configuration file from the provided path
    -C, --config-samedir     Attempt to load wasmut.toml from the same directory as the wasm module
    -h, --help               Print help information
    -V, --version            Print version information

WebAssembly模块要求

wasmut 目前支持使用 WebAssembly系统接口(WASI) 的WebAssembly模块。 wasmut 将以 _start 函数作为模块的入口点执行,并将模块的退出代码(由 main 的返回值或显式调用 exit 设置)用于确定模块测试的结果 - 0 表示成功,任何非零退出代码表示失败。

wasmut 在突变过滤和报告生成方面大量使用 DWARF 调试信息。请确保使用正确的编译器标志编译 WebAssembly 模块,以确保调试信息嵌入到模块中。

此外,编译器优化对 wasmut 的性能有很强的影响。需要做更多实验才能给出建议,但到目前为止,请参考 testdata 目录中的示例,了解应使用哪些编译器选项。

配置选项

[engine] 部分

  • timeout_multiplier:在执行突变之前,wasmut 将在没有突变的情况下运行 wasm 模块,并测量执行所需的时间周期数。突变允许以 timeout = original_cycles * timeout_multiplier 的超时时间执行。

    timeout_multiplier = 2.0
    
  • map_dirs:将目录映射到 WebAssembly 运行时。默认情况下,模块无法访问宿主机的文件系统。如果您的模块需要访问任何文件,您可以使用 map_dirs 选项来定义路径映射。

    # Map testdata/count_words/files to /files
    map_dirs = [["testdata/count_words/files", "files"],]
    
  • coverage_based_execution:在执行突变之前,wasmut 将在没有突变的情况下运行 wasm 模块,并生成覆盖率信息。如果启用了 coverage_based_execution,则将跳过突变执行中从未执行过的突变指令。默认为 true

    coverage_based_execution = true
    
  • meta_mutant:如果启用了 meta_mutant,将生成包含所有突变的单个突变。在执行过程中,通过设置标志来激活突变。这种方法的优点是只需要编译单个突变,因此执行时间显著减少。默认为 true

    meta_mutant = true
    

[filter] 部分

  • allowed_function/allowed_file:默认情况下,所有文件和函数都允许,这意味着每个WebAssembly指令都可能被修改。这并不太实用,因此可以指定允许列表来指定函数和/或文件。在allowed_functions和allowed_files中,您可以指定用于匹配函数和文件名的正则表达式列表。如果wasm-instruction的函数或文件至少匹配一个对应的正则表达式,则允许修改该指令。空的正则表达式也匹配所有内容。使用wasmut list-fileswasmut list-functions命令获取wasm模块中所有函数和文件的列表。

    allowed_functions = ["^add"]
    allowed_files = ["src/add.c", "src/main.c"]
    

[operators]部分

  • enabled_operators:默认情况下,所有运算符都允许。如果您不希望如此,可以使用enabled_operators选项来指定应启用哪些运算符。该选项是一个正则表达式列表。使用wasmut list-operators命令或查阅文档以获取所有运算符的列表。

    # Enable binop_sub_to_add and all relop_* operators
    enabled_operators = ["binop_sub_to_add", "relop"]
    

[report]部分

  • path_rewrite:在生成报告时,wasmut需要访问原始源文件。wasmut使用嵌入在WebAssembly模块中的DWARF调试信息来定位它们。由于DWARF将源文件的绝对路径嵌入到模块中,如果您想为在其他主机上构建的WebAssembly模块生成报告,这可能会出现问题。path_rewrite选项允许指定一个正则表达式和一个替换,该替换将在创建报告之前应用于任何源文件路径。内部使用Rust的Regex::replace。有关任何高级替换场景,请查阅文档

    # Replace /home/user/wasmut/ with "build"
    # e.g. /home/user/test/main.c -> 
    #      build/test/main.c
    path_rewrite = ["^/home/user/", "build"]
    

完整示例

[engine]
timeout_multiplier = 4.0
map_dirs = [["testdata/count_words/files", "files"],]
coverage_based_execution = true
meta_mutant = true

[filter]
allowed_functions = ["^count_words"]
#allowed_files = [""]

[operators]
enabled_operators = ["binop_sub_to_add", "relop"]

[report]
path_rewrite = ["^.*/wasmut/", ""]

支持的变异运算符

wasmut中可用的变异运算符目前主要基于mull的运算符

名称 描述
binop_sub_to_add 用加法替换减法
binop_add_to_sub 用减法替换加法
binop_mul_to_div 用有符号/无符号除法替换乘法
binop_div_to_mul 用乘法替换有符号/无符号除法
binop_shl_to_shr 用有符号/无符号右移替换位左移
binop_shr_to_shl 用有符号/无符号左移替换位右移
binop_rem_to_div 用同符号的除法替换余数
binop_div_to_rem 用同符号的除法替换余数
binop_and_to_or 用或替换与
binop_or_to_and 用与替换或
binop_xor_to_or 用或替换异或
binop_or_to_xor 用异或替换或
binop_rotl_to_rotr 用位右旋转替换位左旋转
binop_rotr_to_rotl 用位左旋转替换位右旋转
unop_neg_to_nop 用nop替换一元否定
relop_eq_to_ne 用不等式替换相等测试
relop_ne_to_eq 用相等测试替换不等式
relop_le_to_gt 用同符号的大于替换小于等于
relop_le_to_lt 用同符号的小于替换小于等于
relop_lt_to_ge 用同符号的大于等于替换小于
relop_lt_to_le 用同符号的小于等于替换小于
relop_ge_to_gt 将大于等于替换为相同符号位的大于
relop_ge_to_lt 将大于替换为相同符号位的小于
relop_gt_to_ge 将大于替换为相同符号位的大于等于
relop_gt_to_le 将大于替换为相同符号位的小于等于
const_replace_zero 将零常量替换为42
const_replace_nonzero 将非零常量替换为0
call_remove_void_call 删除对无返回值的函数的调用
call_remove_scalar_call 删除对返回单个标量且值为42的函数的调用

作者

wasmut 由 Lukas Wagner 开发。

许可证

版权所有 © 2021-2022 Lukas Wagner。

所有代码均受MIT许可协议的许可。更多信息请参阅 LICENSE.txt 文件。

依赖项

~27–41MB
~678K SLoC