Skip to content

Commit 614eb77

Browse files
authored
Add simple ensures, requires, safety predicates (#15)
I also added one proof-of-concept harness to ensure Kani can verify it.
1 parent 3a164b0 commit 614eb77

File tree

12 files changed

+173
-1
lines changed

12 files changed

+173
-1
lines changed

.github/workflows/kani.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ jobs:
2626
matrix:
2727
# Kani does not support windows.
2828
os: [ubuntu-latest, macos-latest]
29+
include:
30+
- os: ubuntu-latest
31+
base: ubuntu
32+
- os: macos-latest
33+
base: macos
2934
steps:
3035
- name: Checkout Library
3136
uses: actions/checkout@v4
@@ -41,6 +46,11 @@ jobs:
4146
path: kani
4247
ref: features/verify-rust-std
4348

49+
- name: Setup Dependencies
50+
working-directory: kani
51+
run: |
52+
./scripts/setup/${{ matrix.base }}/install_deps.sh
53+
4454
- name: Build `Kani`
4555
working-directory: kani
4656
run: |
@@ -52,5 +62,6 @@ jobs:
5262
env:
5363
RUST_BACKTRACE: 1
5464
run: |
55-
kani verify-std -Z unstable-options ./library --target-dir "target"
65+
kani verify-std -Z unstable-options ./library --target-dir ${{ runner.temp }} -Z function-contracts \
66+
-Z mem-predicates -Z ptr-to-ref-cast-checks
5667

.github/workflows/rustc.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ jobs:
6161
6262
- name: Run tests
6363
working-directory: upstream
64+
env:
65+
# Avoid error due to unexpected `cfg`.
66+
RUSTFLAGS: "--check-cfg cfg(kani) --check-cfg cfg(feature,values(any()))"
6467
run: |
6568
./configure --set=llvm.download-ci-llvm=true
6669
./x test --stage 0 library/std

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Session.vim
2626
*.rlib
2727
*.rmeta
2828
*.mir
29+
Cargo.lock
2930

3031
## Temporary files
3132
*~

library/contracts/safety/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright Kani Contributors
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
[package]
5+
name = "safety"
6+
version = "0.1.0"
7+
edition = "2021"
8+
license = "MIT OR Apache-2.0"
9+
10+
[lib]
11+
proc-macro = true
12+
13+
[dependencies]
14+
proc-macro2 = "1.0"
15+
proc-macro-error = "1.0.4"
16+
quote = "1.0.20"
17+
syn = { version = "2.0.18", features = ["full"] }

library/contracts/safety/build.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main() {
2+
// We add the configurations here to be checked.
3+
println!("cargo:rustc-check-cfg=cfg(kani_host)");
4+
}

library/contracts/safety/src/kani.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use proc_macro::{TokenStream};
2+
use quote::{quote, format_ident};
3+
use syn::{ItemFn, parse_macro_input};
4+
5+
pub(crate) fn requires(attr: TokenStream, item: TokenStream) -> TokenStream {
6+
rewrite_attr(attr, item, "requires")
7+
}
8+
9+
pub(crate) fn ensures(attr: TokenStream, item: TokenStream) -> TokenStream {
10+
rewrite_attr(attr, item, "ensures")
11+
}
12+
13+
fn rewrite_attr(attr: TokenStream, item: TokenStream, name: &str) -> TokenStream {
14+
let args = proc_macro2::TokenStream::from(attr);
15+
let fn_item = parse_macro_input!(item as ItemFn);
16+
let attribute = format_ident!("{}", name);
17+
quote!(
18+
#[kani_core::#attribute(#args)]
19+
#fn_item
20+
).into()
21+
}

library/contracts/safety/src/lib.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//! Implement a few placeholders for contract attributes until they get implemented upstream.
2+
//! Each tool should implement their own version in a separate module of this crate.
3+
4+
use proc_macro::TokenStream;
5+
use proc_macro_error::proc_macro_error;
6+
7+
#[cfg(kani_host)]
8+
#[path = "kani.rs"]
9+
mod tool;
10+
11+
#[cfg(not(kani_host))]
12+
#[path = "runtime.rs"]
13+
mod tool;
14+
15+
#[proc_macro_error]
16+
#[proc_macro_attribute]
17+
pub fn requires(attr: TokenStream, item: TokenStream) -> TokenStream {
18+
tool::requires(attr, item)
19+
}
20+
21+
#[proc_macro_error]
22+
#[proc_macro_attribute]
23+
pub fn ensures(attr: TokenStream, item: TokenStream) -> TokenStream {
24+
tool::ensures(attr, item)
25+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use proc_macro::TokenStream;
2+
3+
/// For now, runtime requires is a no-op.
4+
///
5+
/// TODO: At runtime the `requires` should become an assert unsafe precondition.
6+
pub(crate) fn requires(_attr: TokenStream, item: TokenStream) -> TokenStream {
7+
item
8+
}
9+
10+
/// For now, runtime requires is a no-op.
11+
///
12+
/// TODO: At runtime the `ensures` should become an assert as well.
13+
pub(crate) fn ensures(_attr: TokenStream, item: TokenStream) -> TokenStream {
14+
item
15+
}

library/core/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ name = "corebenches"
2424
path = "benches/lib.rs"
2525
test = true
2626

27+
[dependencies]
28+
safety = {path = "../contracts/safety" }
29+
2730
[dev-dependencies]
2831
rand = { version = "0.8.5", default-features = false }
2932
rand_xorshift = { version = "0.3.0", default-features = false }

library/core/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,9 @@ mod unit;
431431
#[stable(feature = "core_primitive", since = "1.43.0")]
432432
pub mod primitive;
433433

434+
#[cfg(kani)]
435+
kani_core::kani_lib!(core);
436+
434437
// Pull in the `core_arch` crate directly into core. The contents of
435438
// `core_arch` are in a different repository: rust-lang/stdarch.
436439
//

0 commit comments

Comments
 (0)