-
Notifications
You must be signed in to change notification settings - Fork 95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
kani fails to unwind 2 x 1 elements nested loop in firecracker code #1786
Comments
Thanks for the bug report, @kalyazin ! Unfortunately, this means you need to keep increasing the unwind value until the unwinding failure doesn't show. The reason is that the underlying code may contain loops that you cannot see directly. Have you tried increasing the unwinding value or is does it take too long in that case? |
@adpaco-aws , thanks for getting back. ALLOWED_MSR_RANGES.iter().any(|range| range.contains(index)) ALLOWED_MSR_RANGES has 2 elements now. So the overall complexity is 2 x 1 x 2 which is 4. cargo kani -p arch --enable-unstable=mir-linker --harness test_msr_allowlist --restrict-vtable --unwind 20 I believe unwinding value 20 should be well enough to cover 4 iterations. Am I missing something? |
@kalyazin as I mentioned, the code underneath those methods may contain loops which require a higher unwinding limit. We acknowledge this isn't intuitive at the moment. Our recommendation is:
You can use different strategies in step (1) to find the value that doesn't trigger the unwinding assertion, like doubling the value each time. But it depends very much on the project, and it's not strange to go to values like 256 if the code underneath performs, for example, manipulations over byte streams. Hope this is helpful! |
@adpaco-aws thanks for the suggestion. for msr in range.base..(range.base + range.nmsrs) { with for msr in 0..2 { I am able to run kani with just |
Just an update here. I tried |
This is definitely a bug. Here's a minimal reproducer that exhibits the same behavior: #[kani::proof]
#[kani::unwind(50)]
fn main() {
let a: &[(i32, i32)] = &[(0, 1), (1, 2)];
for e in a {
let lb = e.0;
let ub = e.0 + e.1;
for i in lb..ub {
assert!(i <= 2);
}
}
}
|
This simpler example fails as well: #[cfg_attr(kani, kani::proof, kani::unwind(50))]
fn main() {
let a: &[i32] = &[0, 1];
for e in a {
let lb = *e;
let ub = lb + 1;
for i in lb..ub {
assert!(i <= 2);
}
}
} |
#[cfg_attr(kani, kani::proof, kani::unwind(50))]
fn main() {
let a: &[i32] = &[0, 0];
for &e in a {
assert_eq!(e, 0);
for i in e..1 {
assert_eq!(i, 0);
}
}
} but if I change the outer loop to iterate over the indices, it works fine: #[cfg_attr(kani, kani::proof, kani::unwind(50))]
fn main() {
let a: &[i32] = &[0, 0];
for j in 0..a.len() {
let e = a[j];
assert_eq!(e, 0);
for i in e..1 {
assert_eq!(i, 0);
}
}
}
|
This smaller program also exhibits the same behavior: #[cfg_attr(kani, kani::proof, kani::unwind(20))]
fn main() {
for e in &[0, 0] {
for _i in *e..1 {
}
}
} |
An observation from offline discussions is that adding any dummy statement after the inner loop makes the problem go away, e.g.: #[cfg_attr(kani, kani::proof, kani::unwind(4))]
fn main() {
for e in &[0, 0] {
for _i in *e..1 {
}
assert!(1 + 1 == 2);
}
}
|
Another observation is that the behavior is the same whether we use |
Perhaps there is a bug in this rewriter? Will investigate later on this week. |
It seems that at the goto-program level the loops here form a figure-of-eight. They are two (nested) natural loops, but not two nested lexical loops. |
I have issued a draft PR, which is waiting for me to piece together a test case. |
That PR is now awaiting feedback/approval by code owners. |
The CBMC PR is now merged and will be part of the next release. No changes in Kani should be required, so once you updated to the next CBMC release this issue should be addressed (I suppose you'll want to include a test). |
Adding this to our sprint board so we remember to close it as part of our next release. |
I am running the following command
on this Firecracker version:
firecracker-microvm/firecracker@99f3023
with the attached patch applied, with Kani version: 0.0.1.
I expected for Kani to be able to unwind the nested loop (outer loop is 2 elements, inner loop is 1 element).
Instead, I see the following output:
0001-kani-unwinding-failures.patch.txt
The text was updated successfully, but these errors were encountered: