-
Notifications
You must be signed in to change notification settings - Fork 92
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
Enable an #[safety_constraint(...)]
attribute helper for the Arbitrary
and Invariant
macros
#3283
Enable an #[safety_constraint(...)]
attribute helper for the Arbitrary
and Invariant
macros
#3283
Conversation
Quick question... wouldn't it make sense to also parse this helper in the |
I'm not sure about that. How would users create an unsafe value then? This isn't clear to me and I think it's a use-case we should continue to support. To me, it'd make more sense to have another API |
|
#[invariant(...)]
attribute helper for the #[derive(Invariant)]
macro#[invariant(...)]
attribute helper for the Arbitrary
and Invariant
macros
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Can you please add a test where the invariant calls a function and one that tries to mutate the object? Thank you
tests/ui/derive-invariant/helper-wrong-expr/helper-wrong-expr.rs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I find it a bit unexpected that #[derive(Arbitrary)]
takes invariants from #[invariant]
into account but not those from impl Invariant
.
For example, what happens when the field type already has an #[derive(Arbitrary)]
struct Foo {
#[invariant(*c != 'X')]
c: char,
#[invariant(*i > 2)]
i: i32,
} Would the safety invariant of |
I would still prefer keeping the |
#[invariant(...)]
attribute helper for the Arbitrary
and Invariant
macros#[safety_constaint(...)]
attribute helper for the Arbitrary
and Invariant
macros
#[safety_constaint(...)]
attribute helper for the Arbitrary
and Invariant
macros#[safety_constraint(...)]
attribute helper for the Arbitrary
and Invariant
macros
Update: On a separate discussion, we agreed on keeping the implementation as is while we ensure that the documentation communicates the danger of over-constraining values generated with For the documentation, I've added it to the derive functions so that it's visible in the crates documentation. We could add another section to the "Reference" section of our documentation with this, but I don't know how we could keep them sync'd. We also ensure now that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Do we check anywhere (or need to check) that the annotated field matches with the variable used in the predicate?
For example, does Kani error out in the following case?
struct Foo {
#[safety_constraint(*y == 5)]
x: i32,
y: i32,
}
If not, perhaps the safety constraints can be added anywhere inside the struct and not necessarily annotated on the individual fields?
tests/expected/derive-arbitrary/safety_constraint_helper/safety_constraint_helper.rs
Show resolved
Hide resolved
We don't check the expressions for that. In my opinion, that'd be a nice feature to have but it's not needed at this point.
No, it doesn't error out. We could change it so the safety constraints can be added somewhere else but I don't know what's the advantage. Also, note that the feature in #3270 is expected to allow constraints relating multiple fields of the struct. But if we're talking about constraints associated to individual fields, I think this feature is more appropriate because the annotations are easier to read. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks good to me. Can you please add a test where all the attributes are guarded by kani
configuration. I.e.: #[cfg_attr(kani, safety_attribute(/*content*/))]
.
Other tests that I would like to see is inadvertently specifying an expression with side effect, and mentioning other fields in the invariant expression. Thanks!
tests/expected/derive-invariant/safety_constraint_helper_funs/safety_constraint_helper_funs.rs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!!
This PR defines a struct-level `#[safety_constraint(<pred>)]` macro attribute that allows users to define the type invariant as the predicate passed as an argument to the attribute. This safety constraint is picked up when deriving `Arbitrary` and `Invariant` implementations so that the values generated with `any()` or checked with `is_safe()` satisfy the constraint. This attribute is similar to the helper attribute introduced in #3283, and they cannot be used together. It's preferable to use this attribute when the constraint implies some relation between different fields. But, at the moment, there's no practical difference between them because the helper attribute allows users to refer to any fields. If we imposed that restriction, this attribute would be the only way to specify struct-wide invariants. An example: ```rs #[derive(kani::Arbitrary)] #[derive(kani::Invariant)] #[safety_constraint(*x == *y)] struct SameCoordsPoint { x: i32, y: i32, } #[kani::proof] fn check_invariant() { let point: SameCoordsPoint = kani::any(); assert!(point.is_safe()); } ``` Resolves #3095
## 0.54.0 ### Major Changes * We added support for slices in the `#[kani::modifies(...)]` clauses when using function contracts. * We introduce an `#[safety_constraint(...)]` attribute helper for the `Arbitrary` and `Invariant` macros. * We enabled support for concrete playback for harness that contains stubs or function contracts. * We added support for log2*, log10*, powif*, fma*, and sqrt* intrisincs. ### Breaking Changes * The `-Z ptr-to-ref-cast-checks` option has been removed, and pointer validity checks when casting raw pointers to references are now run by default. ## What's Changed * Make Kani reject mutable pointer casts if padding is incompatible and memory initialization is checked by @artemagvanian in #3332 * Fix visibility of some Kani intrinsics by @artemagvanian in #3323 * Function Contracts: Modify Slices by @pi314mm in #3295 * Support for disabling automatically generated pointer checks to avoid reinstrumentation by @artemagvanian in #3344 * Add support for global transformations by @artemagvanian in #3348 * Enable an `#[safety_constraint(...)]` attribute helper for the `Arbitrary` and `Invariant` macros by @adpaco-aws in #3283 * Fix contract handling of promoted constants and constant static by @celinval in #3305 * Bump CBMC Viewer to 3.9 by @tautschnig in #3373 * Update to CBMC version 6.1.1 by @tautschnig in #2995 * Define a struct-level `#[safety_constraint(...)]` attribute by @adpaco-aws in #3270 * Enable concrete playback for contract and stubs by @celinval in #3389 * Add code scanner tool by @celinval in #3120 * Enable contracts in associated functions by @celinval in #3363 * Enable log2*, log10* intrinsics by @tautschnig in #3001 * Enable powif* intrinsics by @tautschnig in #2999 * Enable fma* intrinsics by @tautschnig in #3002 * Enable sqrt* intrinsics by @tautschnig in #3000 * Remove assigns clause for ZST pointers by @carolynzech in #3417 * Instrumentation for delayed UB stemming from uninitialized memory by @artemagvanian in #3374 * Unify kani library and kani core logic by @jaisnan in #3333 * Stabilize pointer-to-reference cast validity checks by @artemagvanian in #3426 * Rust toolchain upgraded to `nightly-2024-08-07` by @jaisnan @qinheping @tautschnig @feliperodri ## New Contributors * @carolynzech made their first contribution in #3387 **Full Changelog**: kani-0.53.0...kani-0.54.0 By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. Signed-off-by: Felipe R. Monteiro <felisous@amazon.com>
This PR enables an
#[safety_constraint(...)]
attribute helper for the#[derive(Arbitrary)]
and#[derive(Invariant)]
macro.For the
Invariant
derive macro, this allows users to derive more sophisticated invariants for their data types by annotating individual named fields with the#[safety_constraint(<cond>)]
attribute, where<cond>
represents the predicate to be evaluated for the corresponding field. In addition, the implementation always checks#field.is_safe()
for each field.For example, let's say we are working with the
Point
type from #3250and we need to extend it to only allow positive values for both
x
andy
.With the
[safety_constraint(...)]
attribute, we can achieve this without explicitly writing theimpl Invariant for ...
as follows:For the
Arbitrary
derive macro, this allows users to derive more sophisticatedkani::any()
generators that respect the specified invariants. In other words, thekani::any()
will assume any invariants specified through the#[safety_constraint(...)]
attribute helper. Going back to thePositivePoint
example, we'd expect this harness to be successful:The PR includes tests to ensure it's working as expected, in addition to UI tests checking for cases where the arguments provided to the macro are incorrect. Happy to add any other cases that you feel are missing.
Related #3095
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.