Repository navigation
Resolve fn-pointer type arguments in contract target paths #4916
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
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
tests/expected/function-contract/generic_fn_pointer_cabi.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| unable to find implementation of associated function `Probe::probe` for Wrap |
33 changes: 33 additions & 0 deletions
33
tests/expected/function-contract/generic_fn_pointer_cabi.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| // Copyright Kani Contributors | ||
| // SPDX-License-Identifier: Apache-2.0 OR MIT | ||
| // kani-flags: -Zfunction-contracts | ||
|
|
||
| // A fn-pointer argument with a non-Rust ABI is not built by the `Type::BareFn` arm; | ||
| // the path keeps the uninstantiated type and fails to resolve, as before (see | ||
| // tests/kani/FunctionContracts/generic_fn_pointer_argument.rs for the supported cases). | ||
|
|
||
| struct Wrap<T>(T); | ||
|
|
||
| trait Probe { | ||
| fn probe(&self) -> u32; | ||
| } | ||
|
|
||
| impl Probe for Wrap<extern "C" fn(u8) -> u8> { | ||
| #[kani::ensures(|r| *r == 1)] | ||
| fn probe(&self) -> u32 { | ||
| 1 | ||
| } | ||
| } | ||
|
|
||
| mod verify { | ||
| use super::*; | ||
|
|
||
| #[kani::proof_for_contract(<Wrap<extern "C" fn(u8) -> u8> as Probe>::probe)] | ||
| fn check_c_abi_fn_pointer() { | ||
| extern "C" fn id(x: u8) -> u8 { | ||
| x | ||
| } | ||
| let w = Wrap(id as extern "C" fn(u8) -> u8); | ||
| let _ = w.probe(); | ||
| } | ||
| } |
1 change: 1 addition & 0 deletions
1
tests/expected/function-contract/generic_fn_pointer_higher_ranked.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| is not reachable from the harness |
39 changes: 39 additions & 0 deletions
39
tests/expected/function-contract/generic_fn_pointer_higher_ranked.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| // Copyright Kani Contributors | ||
| // SPDX-License-Identifier: Apache-2.0 OR MIT | ||
| // kani-flags: -Zfunction-contracts | ||
|
|
||
| // FIXME: a higher-ranked fn-pointer target mis-resolves to a coexisting `'static` | ||
| // sibling impl. `resolve_ty` erases the fn pointer's lifetimes, so | ||
| // `<Wrap<fn(&u8) -> u8> as Probe>::probe` resolves to the `fn(&'static u8) -> u8` | ||
| // impl instead of its own, and `h_hr` cannot reach its target. Binding the late-bound | ||
| // regions (so the higher-ranked type stays distinct) is tracked at | ||
| // https://github.com/model-checking/kani/issues/4933. Both impls can coexist (rustc | ||
| // only warns with `coherence_leak_check`). | ||
| #![allow(coherence_leak_check)] | ||
|
|
||
| struct Wrap<T>(T); | ||
| trait Probe { | ||
| fn probe(&self) -> u32; | ||
| } | ||
|
|
||
| impl Probe for Wrap<fn(&u8) -> u8> { | ||
| #[kani::ensures(|r| *r == 7)] | ||
| fn probe(&self) -> u32 { | ||
| 7 | ||
| } | ||
| } | ||
|
|
||
| impl Probe for Wrap<fn(&'static u8) -> u8> { | ||
| #[kani::ensures(|r| *r == 9)] | ||
| fn probe(&self) -> u32 { | ||
| 9 | ||
| } | ||
| } | ||
|
|
||
| #[kani::proof_for_contract(<Wrap<fn(&u8) -> u8> as Probe>::probe)] | ||
| fn h_hr() { | ||
| fn d(x: &u8) -> u8 { | ||
| *x | ||
| } | ||
| let _ = Wrap(d as fn(&u8) -> u8).probe(); | ||
| } |
77 changes: 77 additions & 0 deletions
77
tests/kani/FunctionContracts/generic_fn_pointer_argument.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| // Copyright Kani Contributors | ||
| // SPDX-License-Identifier: Apache-2.0 OR MIT | ||
| // kani-flags: -Zfunction-contracts | ||
|
|
||
| // `proof_for_contract` on a target whose type arguments include a fn-pointer type. | ||
| // `resolve_ty` now builds the fn-pointer type from a `Type::BareFn` argument (Rust ABI, | ||
| // non-variadic; lifetimes erased like every other path argument), so these resolve and | ||
| // verify: | ||
| // * a plain fn-pointer argument (`fn(u8) -> u8`), | ||
| // * a reference-carrying fn pointer (`fn(&u8) -> u8`), whose impl's stored type is | ||
| // late-bound (`for<'a> fn(&'a u8) -> u8`); the erased argument matches it when no | ||
| // `fn(&'static u8) -> u8` sibling impl exists (see generic_fn_pointer_higher_ranked.rs), | ||
| // * an `unsafe` fn pointer (safety carried through the built signature). | ||
| // The two safe impls have distinct postconditions, so each harness only verifies if | ||
| // resolution picks *its* fn-pointer instantiation, not merely one of them. | ||
| // `generic_fn_pointer_cabi.rs` (expected suite) guards that a non-Rust-ABI fn pointer | ||
| // keeps the uninstantiated type and still fails to resolve. | ||
|
|
||
| struct Wrap<T>(T); | ||
|
|
||
| trait Probe { | ||
| fn probe(&self) -> u32; | ||
| } | ||
|
|
||
| impl Probe for Wrap<fn(u8) -> u8> { | ||
| #[kani::ensures(|r| *r == 0)] | ||
| fn probe(&self) -> u32 { | ||
| 0 | ||
| } | ||
| } | ||
|
|
||
| // Distinct postcondition from the `fn(u8) -> u8` impl, so a harness only verifies if | ||
| // resolution lands on *this* fn-pointer instantiation rather than the sibling. | ||
| impl Probe for Wrap<fn(&u8) -> u8> { | ||
| #[kani::ensures(|r| *r == 7)] | ||
| fn probe(&self) -> u32 { | ||
| 7 | ||
| } | ||
| } | ||
|
|
||
| impl Probe for Wrap<unsafe fn(u8) -> u8> { | ||
| #[kani::ensures(|r| *r == 3)] | ||
| fn probe(&self) -> u32 { | ||
| 3 | ||
| } | ||
| } | ||
|
|
||
| mod verify { | ||
| use super::*; | ||
|
|
||
| #[kani::proof_for_contract(<Wrap<fn(u8) -> u8> as Probe>::probe)] | ||
| fn check_plain_fn_pointer() { | ||
| fn id(x: u8) -> u8 { | ||
| x | ||
| } | ||
| let w = Wrap(id as fn(u8) -> u8); | ||
| let _ = w.probe(); | ||
| } | ||
|
|
||
| #[kani::proof_for_contract(<Wrap<fn(&u8) -> u8> as Probe>::probe)] | ||
| fn check_reference_carrying_fn_pointer() { | ||
| fn deref(x: &u8) -> u8 { | ||
| *x | ||
| } | ||
| let w = Wrap(deref as fn(&u8) -> u8); | ||
| let _ = w.probe(); | ||
| } | ||
|
|
||
| #[kani::proof_for_contract(<Wrap<unsafe fn(u8) -> u8> as Probe>::probe)] | ||
| fn check_unsafe_fn_pointer() { | ||
| unsafe fn id(x: u8) -> u8 { | ||
| x | ||
| } | ||
| let w = Wrap(id as unsafe fn(u8) -> u8); | ||
| let _ = w.probe(); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.