Skip to content

Commit b904508

Browse files
authored
Merge pull request coconut-svsm#1038 from ziqiaozhou/cargo-verus
[verification] Support Verus's verita test via cargo-verus.
2 parents eaa49a4 + 2e8cf5b commit b904508

11 files changed

Lines changed: 189 additions & 64 deletions

File tree

.cargo/config.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ rustflags = [
1414
]
1515

1616
[alias]
17-
verify = "v build --features verus"
17+
verify = "verus focus --features verus"
1818
xbuild = "run --package xbuild --release --"

.github/workflows/manual-verify.yml

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,10 @@ jobs:
3636
run: |
3737
verusfmt --check `find ./ -name *.verus.rs` --verus-only
3838
39-
# cargo-v doesn't propagate the `cargo build` exit code, so we need
40-
# to check stderr for errors.
41-
# When https://github.com/microsoft/verismo/issues/23 will be fixed
42-
# we can remove it.
4339
- name: Verify svsm with verus
44-
run: |
45-
cargo verify 2>&1 | tee verify.log
46-
! grep -q 'cargo build failed' verify.log
40+
run: cargo verify
4741
working-directory: kernel
4842

4943
- name: Verify extra proof libs with verus
50-
run: |
51-
cargo verify 2>&1 | tee verify.log
52-
! grep -q 'cargo build failed' verify.log
44+
run: cargo verify
5345
working-directory: verification/verify_proof

Cargo.lock

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ zerocopy = { version = "0.8.2", features = ["derive"] }
101101
embedded-io = { version = "0.6.1" }
102102

103103
# Verus repos
104-
verus_builtin = { version = "=0.0.0-2025-12-07-0054", default-features = false }
105-
verus_builtin_macros = { version = "=0.0.0-2025-12-07-0054", features = ["vpanic"], default-features = false }
106-
verus_state_machines_macros = { version = "=0.0.0-2025-11-23-0053", default-features = false }
107-
vstd = { version = "0.0.0-2025-12-07-0054", features = ["alloc", "allow_panic"], default-features = false }
104+
verus_builtin = { version = "=0.0.0-2026-04-12-0118", default-features = false }
105+
verus_builtin_macros = { version = "=0.0.0-2026-04-12-0118", features = ["vpanic"], default-features = false }
106+
verus_state_machines_macros = { version = "=0.0.0-2026-04-05-0114", default-features = false }
107+
vstd = { version = "=0.0.0-2026-04-12-0118", features = ["alloc", "allow_panic"], default-features = false }
108108

109109
# Verification libs
110110
verify_proof = { path = "verification/verify_proof", default-features = false }

Documentation/docs/developer/VERIFICATION.md

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,18 @@ Run the following commands to install Verus tools.
3131

3232
```shell
3333
cd svsm
34-
./scripts/vinstall.sh
34+
./scripts/vinstall.sh --use-prebuilt
3535
```
3636

37+
The script skips installation if a matching version of Verus is already installed.
38+
To force reinstallation (e.g., some verus-related tools are missing), add the --force flag.
39+
To build both Verus and Z3 from source instead of using prebuilt binaries, omit the --use-prebuilt flag. Building from source is required for CI.
40+
41+
> Can I use latest Verus toolchain?
42+
>> The `vinstall.sh` script and our Cargo dependencies are pinned to a specific
43+
Verus version, but newer releases may work as well. Verus runs cross-project CI
44+
to check whether new Verus changes remain compatible with Coconut SVSM.
45+
3746
> Why am I using a different Rust toolchain?
3847
>> Verus requires a specific version of Rust (e.g., 1.88.0) because it depends
3948
on the compiler’s internal libraries for verification. Thanks to Rust’s strong
@@ -50,29 +59,28 @@ cd svsm/kernel
5059
cargo verify
5160
```
5261

53-
By default, it only verifies the current crate (`cargo verify` is an alias of `cargo v --features verus`), while using spec/proof from external crates. To verify all external crates, run `cargo v --features verusall`
54-
55-
62+
By default, `cargo verify` verifies only the current crate. It is an alias for
63+
`cargo verus focus --features verus` and uses specifications and proofs from
64+
dependency crates without re-verifying them. To verify dependency crates as
65+
well, run `cargo verus verify --features verus`.
5666

5767
### Pass verus arguments for verification
5868

5969
For debugging purposes, it is helpful to pass additional Verus arguments.
60-
You can specify extra arguments using the environmental variable
61-
{crate}_{lib/bin}_VERUS_ARGS for a specific crate
62-
{crate} or VERUS_ARGS for all crates.
70+
You can specify extra arguments using `cargo verify -- $extra_verus_args`
6371

6472
**Examples**
6573

6674
* Compiles a crate without verifying svsm crate using verus compilation:
6775

6876
```shell
69-
svsm_lib_VERUS_ARGS="--no-verify" cargo verify
77+
cargo verify -- --no-verify
7078
```
7179

7280
* Compiles a crate while only verifying address module in svsm crate:
7381

7482
```shell
75-
svsm_lib_VERUS_ARGS="--verify-module address --verify-function VirtAddr::new" cargo verify
83+
cargo verify -- --verify-only-module address --verify-function VirtAddr::new
7684
```
7785

7886
### Build without verification

kernel/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,8 @@ sha2 = { workspace = true, features = ["force-soft"] }
8787
[build-dependencies]
8888
rustc_version = "0.4"
8989

90+
[package.metadata.verus]
91+
verify = true
92+
9093
[lints]
9194
workspace = true

kernel/src/mm/alloc.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,7 @@ enum PageType {
9595
#[verus_verify]
9696
impl TryFrom<u64> for PageType {
9797
type Error = AllocError;
98-
#[verus_spec(ret =>
99-
ensures
100-
PageType::ens_try_from(val, ret),
101-
)]
98+
#[verus_spec]
10299
fn try_from(val: u64) -> Result<Self, Self::Error> {
103100
match val {
104101
v if v == Self::Free as u64 => Ok(Self::Free),
@@ -1210,7 +1207,7 @@ impl HeapMemoryRegion {
12101207
old(self).req_allocate_pfn(pfn, order)
12111208
ensures
12121209
ret.is_ok() ==> old(self).ens_allocate_pfn(self, pfn, order, *perm),
1213-
!ret.is_ok() ==> old(self) === self,
1210+
!ret.is_ok() ==> *old(self) === *self,
12141211
)]
12151212
#[verus_verify(spinoff_prover, rlimit(2))]
12161213
fn allocate_pfn(&mut self, pfn: usize, order: usize) -> Result<(), AllocError> {
@@ -1242,7 +1239,7 @@ impl HeapMemoryRegion {
12421239

12431240
#[cfg_attr(verus_keep_ghost, verus_spec(
12441241
invariant
1245-
self === old(self),
1242+
*self === *old(self),
12461243
self.wf_next_pages(),
12471244
self.req_allocate_pfn(pfn, order),
12481245
self.req_allocate_pfn(old_pfn, order),

kernel/src/mm/alloc_types.verus.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
// Proves the encode/decode functions for PageInfo used in alloc.rs.
88
use vstd::simple_pptr::MemContents;
9+
use vstd::std_specs::convert::TryFromSpec;
910
verus! {
1011

1112
// prove the size of PageStorageType
@@ -408,22 +409,21 @@ impl SpecDecoderProof<PageStorageType> for ReservedInfo {
408409
}
409410
}
410411

411-
impl PageType {
412-
spec fn spec_try_from(val: u64) -> Option<Self> {
413-
match val {
414-
v if v == Self::Free as u64 => Some(Self::Free),
415-
v if v == Self::Allocated as u64 => Some(Self::Allocated),
416-
v if v == Self::SlabPage as u64 => Some(Self::SlabPage),
417-
v if v == Self::Compound as u64 => Some(Self::Compound),
418-
v if v == Self::File as u64 => Some(Self::File),
419-
v if v == Self::Reserved as u64 => Some(Self::Reserved),
420-
_ => None,
421-
}
412+
impl vstd::std_specs::convert::TryFromSpecImpl<u64> for PageType {
413+
closed spec fn obeys_try_from_spec() -> bool {
414+
true
422415
}
423416

424-
pub closed spec fn ens_try_from(val: u64, ret: Result<Self, AllocError>) -> bool {
425-
&&& ret.is_ok() == PageType::spec_try_from(val).is_some()
426-
&&& ret.is_ok() ==> ret.unwrap() == PageType::spec_try_from(val).unwrap()
417+
closed spec fn try_from_spec(val: u64) -> Result<Self, Self::Error> {
418+
match val {
419+
v if v == Self::Free as u64 => Ok(Self::Free),
420+
v if v == Self::Allocated as u64 => Ok(Self::Allocated),
421+
v if v == Self::SlabPage as u64 => Ok(Self::SlabPage),
422+
v if v == Self::Compound as u64 => Ok(Self::Compound),
423+
v if v == Self::File as u64 => Ok(Self::File),
424+
v if v == Self::Reserved as u64 => Ok(Self::Reserved),
425+
_ => Err(AllocError::InvalidPageType),
426+
}
427427
}
428428
}
429429

@@ -434,7 +434,7 @@ impl SpecDecoderProof<PageStorageType> for PageType {
434434

435435
spec fn spec_decode(mem: PageStorageType) -> Option<Self> {
436436
let val = mem.0 & PageStorageType::TYPE_MASK;
437-
PageType::spec_try_from(val)
437+
PageType::try_from_spec(val).ok()
438438
}
439439

440440
proof fn lemma_encode_decode(&self) {

0 commit comments

Comments
 (0)