Skip to content

Commit d9e84ef

Browse files
celinvaltedinski
authored andcommitted
Add support to verify test harness (rust-lang#664) (rust-lang#672)
This resolves rust-lang#664. I added an argument to rmc and cargo rmc (--tests) to allow users to target test harnesses as their verification function.
1 parent 2b893fe commit d9e84ef

File tree

6 files changed

+68
-61
lines changed

6 files changed

+68
-61
lines changed

scripts/cargo-rmc

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ def main():
2424
rmc.ensure_dependencies_in_path()
2525

2626
if args.gen_c_runnable:
27-
rmc.cargo_build(args.crate, args.target_dir, args.build_target,
28-
args.verbose, args.debug, args.mangler, args.dry_run, ["gen-c"], args.restrict_vtable)
27+
rmc.cargo_build(args.crate, args.target_dir, args, ["gen-c"])
2928

3029
pattern = os.path.join(args.target_dir, "debug", "deps", "*.symtab.json")
3130
symbol_table_jsons = glob.glob(pattern)
@@ -51,8 +50,7 @@ def main():
5150

5251
rmc.gen_c_postprocess(c_runnable_filename, args.dry_run)
5352

54-
rmc.cargo_build(args.crate, args.target_dir, args.build_target,
55-
args.verbose, args.debug, args.mangler, args.dry_run, [], args.restrict_vtable)
53+
rmc.cargo_build(args.crate, args.target_dir, args)
5654

5755
if args.build_target:
5856
pattern = os.path.join(args.target_dir, args.build_target, "debug", "deps", "*.symtab.json")

scripts/rmc

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,7 @@ def main():
2828
json_runnable_filename = base + "_runnable.json"
2929
goto_runnable_filename = base + "_runnable.goto"
3030
c_runnable_filename = base + "_runnable.c"
31-
if EXIT_CODE_SUCCESS != rmc.compile_single_rust_file(
32-
args.input,
33-
base,
34-
json_runnable_filename,
35-
args.verbose,
36-
args.debug,
37-
args.keep_temps,
38-
args.mangler,
39-
args.dry_run,
40-
["gen-c"],
41-
args.restrict_vtable):
31+
if EXIT_CODE_SUCCESS != rmc.compile_single_rust_file(args.input, base, json_runnable_filename, args, ["gen-c"]):
4232
return 1
4333

4434
out_files = rmc.symbol_table_to_gotoc([json_runnable_filename], args.verbose, args.keep_temps, args.dry_run)
@@ -63,20 +53,7 @@ def main():
6353
symbols_filename = base + ".symbols"
6454

6555
restrictions_filename = restrictions_filename if args.restrict_vtable else None
66-
67-
if EXIT_CODE_SUCCESS != rmc.compile_single_rust_file(
68-
args.input,
69-
base,
70-
symbol_table_json_filename,
71-
args.verbose,
72-
args.debug,
73-
args.keep_temps,
74-
args.mangler,
75-
args.dry_run,
76-
args.use_abs,
77-
args.abs_type,
78-
[],
79-
args.restrict_vtable):
56+
if EXIT_CODE_SUCCESS != rmc.compile_single_rust_file(args.input, base, symbol_table_json_filename, args):
8057
return 1
8158

8259
out_files = rmc.symbol_table_to_gotoc([symbol_table_json_filename], args.verbose, args.keep_temps, args.dry_run)

scripts/rmc.py

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -222,46 +222,44 @@ def compile_single_rust_file(
222222
input_filename,
223223
base,
224224
output_filename,
225-
verbose=False,
226-
debug=False,
227-
keep_temps=False,
228-
mangler="v0",
229-
dry_run=False,
230-
use_abs=False,
231-
abs_type="std",
232-
symbol_table_passes=[],
233-
restrict_vtable=False):
234-
if not keep_temps:
225+
226+
extra_args,
227+
symbol_table_passes=[]):
228+
if not extra_args.keep_temps:
235229
atexit.register(delete_file, output_filename)
236230
atexit.register(delete_file, base + ".type_map.json")
237231

238-
build_cmd = [RMC_RUSTC_EXE] + rustc_flags(mangler, symbol_table_passes, restrict_vtable)
232+
build_cmd = [RMC_RUSTC_EXE] + rustc_flags(extra_args.mangler, symbol_table_passes,
233+
extra_args.restrict_vtable)
239234

240-
if use_abs:
235+
if extra_args.use_abs:
241236
build_cmd += ["-Z", "force-unstable-if-unmarked=yes",
242237
"--cfg=use_abs",
243-
"--cfg", f'abs_type="{abs_type}"']
238+
"--cfg", f'abs_type="{extra_args.abs_type}"']
239+
240+
if extra_args.tests and "--test" not in build_cmd:
241+
build_cmd += ["--test"]
244242

245243
build_cmd += ["-o", base + ".o", input_filename]
246244

247245
build_env = os.environ
248-
if debug:
246+
if extra_args.debug:
249247
add_rmc_rustc_debug_to_env(build_env)
250248

251-
return run_cmd(build_cmd, env=build_env, label="compile", verbose=verbose, debug=debug, dry_run=dry_run)
249+
return run_cmd(
250+
build_cmd,
251+
env=build_env,
252+
label="compile",
253+
verbose=extra_args.verbose,
254+
debug=extra_args.debug,
255+
dry_run=extra_args.dry_run)
252256

253257
# Generates a symbol table (and some other artifacts) from a rust crate
254258
def cargo_build(
255259
crate,
256260
target_dir,
257-
build_target=None,
258-
verbose=False,
259-
debug=False,
260-
mangler="v0",
261-
dry_run=False,
262-
symbol_table_passes=[],
263-
restrict_vtable=False):
264-
261+
extra_args,
262+
symbol_table_passes=[]):
265263
ensure(os.path.isdir(crate), f"Invalid path to crate: {crate}")
266264

267265
def get_config(option):
@@ -277,23 +275,28 @@ def get_config(option):
277275
process.stdout))
278276
return process.stdout
279277

280-
rustflags = rustc_flags(mangler, symbol_table_passes, restrict_vtable) + get_config("--rmc-flags").split()
278+
rustflags = rustc_flags(extra_args.mangler, symbol_table_passes,
279+
extra_args.restrict_vtable) + get_config("--rmc-flags").split()
281280
rustc_path = get_config("--rmc-path").strip()
282-
build_cmd = ["cargo", "build", "--target-dir", str(target_dir)]
283-
if build_target:
284-
build_cmd += ["--target", str(build_target)]
281+
cargo_cmd = ["cargo", "build"] if not extra_args.tests else ["cargo", "test", "--no-run"]
282+
build_cmd = cargo_cmd + ["--target-dir", str(target_dir)]
283+
if extra_args.build_target:
284+
build_cmd += ["--target", str(extra_args.build_target)]
285285
build_env = os.environ
286286
build_env.update({"RUSTFLAGS": " ".join(rustflags),
287287
"RUSTC": rustc_path
288288
})
289-
if debug:
289+
if extra_args.debug:
290290
add_rmc_rustc_debug_to_env(build_env)
291-
if verbose:
291+
if extra_args.verbose:
292292
build_cmd.append("-v")
293-
if dry_run:
293+
if extra_args.dry_run:
294294
print("{}".format(build_env))
295295

296-
return run_cmd(build_cmd, env=build_env, cwd=crate, label="build", verbose=verbose, debug=debug, dry_run=dry_run)
296+
if run_cmd(build_cmd, env=build_env, cwd=crate, label="build", verbose=extra_args.verbose, debug=extra_args.debug,
297+
dry_run=extra_args.dry_run) != EXIT_CODE_SUCCESS:
298+
raise Exception("Failed to run command: {}".format(" ".join(build_cmd)))
299+
297300

298301
# Adds information about unwinding to the RMC output
299302
def append_unwind_tip(text):

scripts/rmc_flags.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ def add_linking_flags(make_group, add_flag, config):
112112
help="Link external C files referenced by Rust code")
113113
add_flag(group, "--function", default="main",
114114
help="Entry point for verification")
115+
add_flag(group, "--tests", default=False, action=BooleanOptionalAction,
116+
help="Enable test function verification. Only use this option when the entry point is a test function.")
115117

116118
# Add flags that produce extra artifacts.
117119
def add_artifact_flags(make_group, add_flag, config):

src/test/rmc/ArithOperators/unsafe_mul_fail.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// rmc-flags: --function check_mul
77
// compile-flags: --crate-type lib
88

9-
pub fn check_add(a: u8, b: u8) {
9+
pub fn check_mul(a: u8, b: u8) {
1010
unsafe {
1111
a * b;
1212
}

src/test/rmc/Options/check_tests.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
// Check that we can verify test harnesses using the --tests argument.
5+
// Note: We need to provide the compile-flags because compile test runs rustc directly and via rmc.
6+
7+
// compile-flags: --test
8+
// rmc-flags: --tests --function test_harness
9+
10+
pub mod my_mod {
11+
pub fn fn_under_verification(a: i32) {
12+
assert!(a > 0);
13+
}
14+
}
15+
16+
#[cfg(test)]
17+
mod test {
18+
use my_mod::fn_under_verification;
19+
20+
#[test]
21+
#[no_mangle]
22+
fn test_harness() {
23+
let input: i32 = rmc::nondet();
24+
rmc::assume(input > 1);
25+
fn_under_verification(input);
26+
}
27+
}

0 commit comments

Comments
 (0)