Skip to content

Commit 4db1b09

Browse files
authored
Expand supported crate-type check (rust-lang#1912)
This change add support to rlib libraries and add proper error handling for crate types that aren't supported. We also no longer crash if there was no supported target found.
1 parent 5a53af1 commit 4db1b09

File tree

19 files changed

+233
-10
lines changed

19 files changed

+233
-10
lines changed

kani-driver/src/call_cargo.rs

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,24 @@
33

44
use crate::args::KaniArgs;
55
use crate::session::{KaniSession, ReachabilityMode};
6-
use anyhow::{Context, Result};
6+
use anyhow::{bail, Context, Result};
77
use cargo_metadata::{Metadata, MetadataCommand, Package};
88
use std::ffi::OsString;
99
use std::fs;
1010
use std::path::{Path, PathBuf};
1111
use std::process::Command;
1212
use tracing::{debug, trace};
1313

14+
//---- Crate types identifier used by cargo.
15+
const CRATE_TYPE_BIN: &str = "bin";
16+
const CRATE_TYPE_CDYLIB: &str = "cdylib";
17+
const CRATE_TYPE_DYLIB: &str = "dylib";
18+
const CRATE_TYPE_LIB: &str = "lib";
19+
const CRATE_TYPE_PROC_MACRO: &str = "proc-macro";
20+
const CRATE_TYPE_RLIB: &str = "rlib";
21+
const CRATE_TYPE_STATICLIB: &str = "staticlib";
22+
const CRATE_TYPE_TEST: &str = "test";
23+
1424
/// The outputs of kani-compiler being invoked via cargo on a project.
1525
pub struct CargoOutputs {
1626
/// The directory where compiler outputs should be directed.
@@ -90,8 +100,8 @@ impl KaniSession {
90100
// Only joing them at the end. All kani flags must come first.
91101
kani_args.extend_from_slice(&rustc_args);
92102

103+
let mut found_target = false;
93104
let packages = packages_to_verify(&self.args, &metadata);
94-
if packages.is_empty() {}
95105
for package in packages {
96106
for target in package_targets(&self.args, package) {
97107
let mut cmd = Command::new("cargo");
@@ -104,9 +114,13 @@ impl KaniSession {
104114
.env("KANIFLAGS", &crate::util::join_osstring(&kani_args, " "));
105115

106116
self.run_terminal(cmd)?;
117+
found_target = true;
107118
}
108119
}
109120

121+
if !found_target {
122+
bail!("No supported targets were found.");
123+
}
110124
if self.args.dry_run {
111125
// mock an answer: mostly the same except we don't/can't expand the globs
112126
return Ok(CargoOutputs {
@@ -184,22 +198,81 @@ impl VerificationTarget {
184198
}
185199

186200
/// Extract the targets inside a package.
201+
///
187202
/// If `--tests` is given, the list of targets will include any integration tests.
203+
///
204+
/// We use the `target.kind` as documented here. Note that `kind` for library will
205+
/// match the `crate-type`, despite them not being explicitly listed in the documentation:
206+
/// <https://docs.rs/cargo_metadata/0.15.0/cargo_metadata/struct.Target.html#structfield.kind>
207+
///
208+
/// The documentation for `crate-type` explicitly states that the only time `kind` and
209+
/// `crate-type` differs is for examples.
210+
/// <https://docs.rs/cargo_metadata/0.15.0/cargo_metadata/struct.Target.html#structfield.crate_types>
188211
fn package_targets(args: &KaniArgs, package: &Package) -> Vec<VerificationTarget> {
189-
package
212+
let mut ignored_tests = vec![];
213+
let mut ignored_unsupported = vec![];
214+
let verification_targets = package
190215
.targets
191216
.iter()
192217
.filter_map(|target| {
193-
debug!(name=?package.name, target=?target.name, kind=?target.kind, "package_targets");
194-
if target.kind.contains(&String::from("bin")) {
218+
debug!(name=?package.name, target=?target.name, kind=?target.kind, crate_type=?target
219+
.crate_types,
220+
"package_targets");
221+
if target.kind.contains(&String::from(CRATE_TYPE_BIN)) {
222+
// Binary targets.
195223
Some(VerificationTarget::Bin(target.name.clone()))
196-
} else if target.kind.contains(&String::from("lib")) {
197-
Some(VerificationTarget::Lib)
198-
} else if target.kind.contains(&String::from("test")) && args.tests {
199-
Some(VerificationTarget::Test(target.name.clone()))
224+
} else if target.kind.contains(&String::from(CRATE_TYPE_LIB))
225+
|| target.kind.contains(&String::from(CRATE_TYPE_RLIB))
226+
{
227+
// Lib targets.
228+
let unsupported_types = target
229+
.kind
230+
.iter()
231+
.filter_map(|kind| {
232+
let kind_str = kind.as_str();
233+
matches!(kind_str,
234+
CRATE_TYPE_CDYLIB | CRATE_TYPE_DYLIB | CRATE_TYPE_STATICLIB |
235+
CRATE_TYPE_PROC_MACRO
236+
).then_some(kind_str)
237+
})
238+
.collect::<Vec<_>>();
239+
if unsupported_types.is_empty() {
240+
Some(VerificationTarget::Lib)
241+
} else {
242+
println!(
243+
"warning: Skipped verification of `{}` due to unsupported crate-type: `{}`.",
244+
target.name,
245+
unsupported_types.join("`, `")
246+
);
247+
None
248+
}
249+
} else if target.kind.contains(&String::from(CRATE_TYPE_TEST)) {
250+
// Test target.
251+
if args.tests {
252+
Some(VerificationTarget::Test(target.name.clone()))
253+
} else {
254+
ignored_tests.push(target.name.as_str());
255+
None
256+
}
200257
} else {
258+
ignored_unsupported.push(target.name.as_str());
201259
None
202260
}
203261
})
204-
.collect()
262+
.collect();
263+
264+
if args.verbose {
265+
// Print targets that were skipped only on verbose mode.
266+
if !ignored_tests.is_empty() {
267+
println!("Skipped the following test targets: '{}'.", ignored_tests.join("', '"));
268+
println!(" -> Use '--tests' to verify harnesses inside a 'test' crate.");
269+
}
270+
if !ignored_unsupported.is_empty() {
271+
println!(
272+
"Skipped the following unsupported targets: '{}'.",
273+
ignored_unsupported.join("', '")
274+
);
275+
}
276+
}
277+
verification_targets
205278
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright Kani Contributors
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
[package]
4+
name = "supported-lib"
5+
version = "0.1.0"
6+
edition = "2021"
7+
description = "Test that Kani correctly handle supported crate types"
8+
9+
[lib]
10+
name = "lib"
11+
crate-type = ["lib", "rlib"]
12+
path = "../src/lib.rs"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Checking harness check_ok...
2+
VERIFICATION:- SUCCESSFUL
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright Kani Contributors
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
[package]
4+
name = "supported-lib"
5+
version = "0.1.0"
6+
edition = "2021"
7+
description = "Test that Kani correctly handle supported crate types"
8+
9+
[lib]
10+
name = "lib"
11+
crate-type = ["lib"]
12+
path = "../src/lib.rs"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Checking harness check_ok...
2+
VERIFICATION:- SUCCESSFUL
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright Kani Contributors
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
[package]
4+
name = "supported-lib"
5+
version = "0.1.0"
6+
edition = "2021"
7+
description = "Test that Kani correctly handle supported crate types"
8+
9+
[lib]
10+
name = "lib"
11+
crate-type = ["rlib"]
12+
path = "../src/lib.rs"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Checking harness check_ok...
2+
VERIFICATION:- SUCCESSFUL
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
// The harness bellow will always succeed. We just want to make sure they are correctly executed.
4+
5+
#[kani::proof]
6+
fn check_ok() {
7+
let b = kani::any();
8+
match b {
9+
true => assert_eq!(b as u8, 1),
10+
false => assert_eq!(b as u8, 0),
11+
}
12+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright Kani Contributors
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
[package]
4+
name = "unsupported-lib"
5+
version = "0.1.0"
6+
edition = "2021"
7+
description = "Test that Kani correctly handle unsupported crate-types"
8+
9+
[lib]
10+
name = "lib"
11+
crate-type = ["cdylib"]
12+
path = "../src/lib.rs"
13+
14+
[package.metadata.kani.flags]
15+
verbose = true
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Skipped the following unsupported targets: 'lib'.
2+
Error: No supported targets were found.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright Kani Contributors
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
[package]
4+
name = "unsupported-lib"
5+
version = "0.1.0"
6+
edition = "2021"
7+
description = "Test that Kani correctly handle unsupported crate-types"
8+
9+
[lib]
10+
name = "lib"
11+
crate-type = ["dylib"]
12+
path = "../src/lib.rs"
13+
14+
[package.metadata.kani.flags]
15+
verbose = true
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Skipped the following unsupported targets: 'lib'.
2+
Error: No supported targets were found.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright Kani Contributors
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
[package]
4+
name = "unsupported-lib"
5+
version = "0.1.0"
6+
edition = "2021"
7+
description = "Test that Kani correctly handle unsupported crate-types"
8+
9+
[lib]
10+
name = "lib"
11+
proc-macro = true
12+
path = "../src/lib.rs"
13+
14+
[package.metadata.kani.flags]
15+
verbose = true
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Skipped the following unsupported targets: 'lib'.
2+
Error: No supported targets were found.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright Kani Contributors
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
[package]
4+
name = "unsupported-lib"
5+
version = "0.1.0"
6+
edition = "2021"
7+
description = "Test that Kani correctly handle unsupported crate-types"
8+
9+
[lib]
10+
name = "lib"
11+
crate-type = ["rlib", "cdylib"]
12+
path = "../src/lib.rs"
13+
14+
[package.metadata.kani.flags]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
warning: Skipped verification of `lib` due to unsupported crate-type: `cdylib`.
2+
Error: No supported targets were found.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
// The harness bellow will be ignored since they are inside an unsupported crate type.
4+
5+
fn fatal_error(msg: &str) -> ! {
6+
panic!("[Error]: {}", msg)
7+
}
8+
9+
#[kani::proof]
10+
fn check_error() {
11+
fatal_error("Oops");
12+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright Kani Contributors
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
[package]
4+
name = "unsupported-lib"
5+
version = "0.1.0"
6+
edition = "2021"
7+
description = "Test that Kani correctly handle unsupported crate-types"
8+
9+
[lib]
10+
name = "lib"
11+
crate-type = ["staticlib"]
12+
path = "../src/lib.rs"
13+
14+
[package.metadata.kani.flags]
15+
verbose = true
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Skipped the following unsupported targets: 'lib'.
2+
Error: No supported targets were found.

0 commit comments

Comments
 (0)