You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We are currently trying to test an initial harness but are having some issues. We confirmed it has a unique name and qualified name, it is under mod verify, and follows the similar syntax of AsciiChar. Appreciate any feedback.
error: no harnesses matched the harness filter: `core::num::nonzero::nonzero_check_new_unchecked`
Our current contract function:
#[requires(n != T::zero())]#[ensures(|result:Self| result.get() == n)]pubconstunsafefnnew_unchecked(n:T) -> Self{matchSelf::new(n){Some(n) => n,None => {// SAFETY: The caller guarantees that `n` is non-zero, so this is unreachable.unsafe{
ub_checks::assert_unsafe_precondition!(
check_language_ub,"NonZero::new_unchecked requires the argument to be non-zero",() => false,);
intrinsics::unreachable()}}}}
Proof for contract:
#[unstable(feature="kani", issue="none")]#[cfg(kani)]mod verify {use core::num::NonZeroI32;// Use core::num instead of std::num// pub const unsafe fn newunchecked(n: T) -> Self#[kani::proof_for_contract(NonZero::new_unchecked)]pubfnnonzero_check_new_unchecked(){let x:i32 = kani::any();// Generates a symbolic value of type i32// Only proceed if x is not zero, because passing zero would violate the precondition
kani::assume(x != 0);unsafe{let _ = NonZeroI32::new_unchecked(x);// Calls NonZero::new_unchecked}}}
@aa-luna I cloned your repository, and when I do the following:
Build Kani from the features/verify-rust-std branch (see here)
Run export PATH=../kani/scripts:$PATH in a terminal window for the verify-rust-std repo (substitute the path to Kani appropriately depending on where yours lives)
I get some compilation errors about your contracts:
error[E0599]: no function or associated item named `zero` found for type parameter `T` in the current scope
--> /Users/cmzech/student/library/core/src/num/nonzero.rs:371:24
|
345 | impl<T> NonZero<T>
| - function or associated item `zero` not found for this type parameter
...
371 | #[requires(n != T::zero())]
| ^^^^ function or associated item not found in `T`
|
= help: items from traits can only be used if the type parameter is bounded by the trait
help: the following trait defines an item `zero`, perhaps you need to restrict type parameter `T` with it:
|
347 | T: ZeroablePrimitive + fmt::num::DisplayInt,
| ++++++++++++++++++++++
error[E0369]: binary operation `==` cannot be applied to type `T`
--> /Users/cmzech/student/library/core/src/num/nonzero.rs:372:43
|
372 | #[ensures(|result: Self| result.get() == n)]
| ------------ ^^ - T
| |
| T
|
help: consider further restricting this bound
|
347 | T: ZeroablePrimitive + cmp::PartialEq,
| ++++++++++++++++
error: aborting due to 2 previous errors
These compilation errors would happen earlier in the pipeline than a harness location issue. I would make sure that you're following the steps above so that rustc is compiling the version of your code with contracts attached. Once you fix these compilation errors, you should be able to run the command in step 3 to run your harness.
I've been doing some work on this. Just finished the basic struct methods like swap_bytes and reverse_bits. On the neg function, I encountered a problem: the neg function takes a NonZero<T> and returns a NonZero<T>. Since negation of a non-zero value always yields a non-zero value, it's a safe function to call. However, the problem is that when negating T::MIN, the value overflows in two's signed complements, and this results in a panic in debug mode, while in release mode T::MIN.neg() == T::MIN. I'm not sure how to handle this in kani, since I added an ensures:
#[inline]#[ensures(|result| result.get() != 0)]fnneg(self) -> Self{// SAFETY: negation of nonzero cannot yield zero values.unsafe{Self::new_unchecked(self.get().neg())}}
Due to the behavior I described above, the ensures field fails for all T::MIN values. Should I special case it like:
#[inline]#[requires(|self| self.get() != $Int::MIN)]#[ensures(|result| result.get() != 0)]fnneg(self) -> Self{// SAFETY: negation of nonzero cannot yield zero values.unsafe{Self::new_unchecked(self.get().neg())}}
or do something else entirely?
Update: It looks like the same is also true for the abs function, where abs(T::MIN) overflows just like neg
I've run into a weird issue on checked_pow and saturating_pow, they are failing with any input where exp is larger than 1 with a failure on the unreachable check in NonZero::new_unchecked (which checks for the case NonZero::new(n) == None):
Check 3: num::nonzero::NonZero::<u16>::new_unchecked.unreachable.2
- Status: FAILURE
- Description: "unreachable code"
- Location: library/core/src/num/nonzero.rs:464:21 in function num::nonzero::NonZero::<u16>::new_unchecked
This seems strange because it implies that the result of the power operation is 0, which is only possible when the base is 0. I've also tested the code manually like
fnmain(){let x = core::num::NonZeroU16::new(1).unwrap();println!("{}", x.saturating_pow(2));println!("{:?}", x.checked_pow(2));}
and it works as would be expected, printing 1 and Some(1). I'm not sure if this is a situation where somehow kani's symbolic execution is diverging from the actual behavior of the code, but that seems unlikely since there's not a lot of places in the code for some UB to exist in order to justify this.
To reproduce the code, add this method to the verify module:
#[kani::proof]pubfnsaturating_pow_1(){let x = NonZeroU16::new(1).unwrap();let pow = 1;
x.saturating_pow(pow);}#[kani::proof]pubfnsaturating_pow_2(){let x = NonZeroU16::new(1).unwrap();let pow = 2;
x.saturating_pow(pow);}
then run ./scripts/run-kani.sh --kani-args --harness nonzero::verify::saturating_pow. saturating_pow_1 passes but saturating_pow_2 doesn't. The specific values of x and pow aren't important, from what I can tell they always fail when pow > 1.
Any guidance on how to debug this would be greatly appreciated!
To the best of our knowledge, Challenge 12 (Safety of NonZero) has been resolved by #637, which has been reviewed, approved, and merged. It verifies all of Part 1 and every Part 2 function across all 12 integer types.
@stefanzetzsche — could you please send a subsequent PR to update the docs (doc/src/challenges/0012-nonzero.md) marking this challenge as Resolved and linking #637 as the winning solution? That doc-update PR can also close this tracking issue.
Two known verification gaps that stem from tool (CBMC) limitations rather than missing work are tracked separately in #656 for future follow-up.
Activity
[-]Tracking Issue for Verification of `NonZero`[/-][+]Challenge 12: Safety of `NonZero`[/+]aa-luna commentedon Sep 15, 2024
We are Team 1 and currently working on this challenge.
PM: Shivani
TL: @aa-luna
Devs: @SahithiMV ; @lang280
aa-luna commentedon Sep 20, 2024
Team,
We are currently trying to test an initial harness but are having some issues. We confirmed it has a unique name and qualified name, it is under mod verify, and follows the similar syntax of AsciiChar. Appreciate any feedback.
Commands:
verify-rust-std/library$ kani verify-std -Z unstable-options "." -Z function-contracts -Z mem-predicates --harness nonzero_check_new_uncheckedand received:
error: no harnesses matched the harness filter: `nonzero_check_new_unchecked`We also tested:
kani verify-std -Z unstable-options "." -Z function-contracts -Z mem-predicates --harness core::num::nonzero::nonzero_check_new_uncheckedand received:
error: no harnesses matched the harness filter: `core::num::nonzero::nonzero_check_new_unchecked`Our current contract function:
Proof for contract:
QinyuanWu commentedon Sep 20, 2024
@aa-luna try
--harness num::nonzero::verify::nonzero_check_new_uncheckedAlso could you point me to the location of your harness?aa-luna commentedon Sep 20, 2024
Thanks, @QinyuanWu, but still did not find. I'm guessing it's a placement issue. We will keep looking around to resolve this.
https://github.com/RustyRelic/verify-rust-std/blob/main/library/core/src/num/nonzero.rs
carolynzech commentedon Sep 20, 2024
@aa-luna I cloned your repository, and when I do the following:
features/verify-rust-stdbranch (see here)export PATH=../kani/scripts:$PATHin a terminal window for theverify-rust-stdrepo (substitute the path to Kani appropriately depending on where yours lives)kani verify-std -Z unstable-options ./library --target-dir /tmp/verify-rust-std -Z function-contracts -Z mem-predicates --harness nonzero_check_new_unchecked 2>&1I get some compilation errors about your contracts:
These compilation errors would happen earlier in the pipeline than a harness location issue. I would make sure that you're following the steps above so that rustc is compiling the version of your code with contracts attached. Once you fix these compilation errors, you should be able to run the command in step 3 to run your harness.
aa-luna commentedon Sep 22, 2024
Issue resolved. Thank you.
NonZero (new_unchecked) Proof for Contract (Init) (#109)
NonZero (rotate_left, rotate_right, max, min, clamp, count_ones, cmp)…
NonZero (unchecked_mul & unchecked_add) Proof for Contracts (#338)
eduardorittner commentedon Oct 14, 2025
Hi! Can I continue work on this even though there are already changes accepted from other contributors?
eduardorittner commentedon Oct 18, 2025
I've been doing some work on this. Just finished the basic struct methods like swap_bytes and reverse_bits. On the neg function, I encountered a problem: the
negfunction takes aNonZero<T>and returns aNonZero<T>. Since negation of a non-zero value always yields a non-zero value, it's a safe function to call. However, the problem is that when negatingT::MIN, the value overflows in two's signed complements, and this results in a panic in debug mode, while in release modeT::MIN.neg() == T::MIN. I'm not sure how to handle this in kani, since I added an ensures:Due to the behavior I described above, the ensures field fails for all
T::MINvalues. Should I special case it like:or do something else entirely?
Update: It looks like the same is also true for the
absfunction, whereabs(T::MIN)overflows just likenegeduardorittner commentedon Oct 23, 2025
I've run into a weird issue on
checked_powandsaturating_pow, they are failing with any input where exp is larger than 1 with a failure on the unreachable check inNonZero::new_unchecked(which checks for the caseNonZero::new(n) == None):This seems strange because it implies that the result of the power operation is 0, which is only possible when the base is 0. I've also tested the code manually like
and it works as would be expected, printing
1andSome(1). I'm not sure if this is a situation where somehow kani's symbolic execution is diverging from the actual behavior of the code, but that seems unlikely since there's not a lot of places in the code for some UB to exist in order to justify this.To reproduce the code, add this method to the
verifymodule:then run
./scripts/run-kani.sh --kani-args --harness nonzero::verify::saturating_pow.saturating_pow_1passes butsaturating_pow_2doesn't. The specific values ofxandpowaren't important, from what I can tell they always fail whenpow > 1.Any guidance on how to debug this would be greatly appreciated!
Challenge 12: Verify safety of NonZero
Challenge 12: Verify safety of NonZero
Challenge 12: Verify safety of NonZero
Challenge 12: Verify safety of NonZero
Challenge 12: Verify safety of NonZero
Challenge 12: safety and correctness of NonZero
feliperodri commentedon Aug 20, 2026
@stefanzetzsche is that ok if I assign this issue to you?
feliperodri commentedon Aug 25, 2026
To the best of our knowledge, Challenge 12 (Safety of
NonZero) has been resolved by #637, which has been reviewed, approved, and merged. It verifies all of Part 1 and every Part 2 function across all 12 integer types.@stefanzetzsche — could you please send a subsequent PR to update the docs (
doc/src/challenges/0012-nonzero.md) marking this challenge as Resolved and linking #637 as the winning solution? That doc-update PR can also close this tracking issue.Two known verification gaps that stem from tool (CBMC) limitations rather than missing work are tracked separately in #656 for future follow-up.
Congratulations again, and thank you! 🎉
Challenge 12: safety and correctness of NonZero (model-checking#637)
docs: mark NonZero challenge as resolved (model-checking#663)