Skip to content

Wrap returned value from codegen_place in a Result to account for the possibility of an error due to unsupported operations#1057

Merged
zhassan-aws merged 5 commits intomodel-checking:mainfrom
zhassan-aws:unimplemented
Apr 19, 2022
Merged

Wrap returned value from codegen_place in a Result to account for the possibility of an error due to unsupported operations#1057
zhassan-aws merged 5 commits intomodel-checking:mainfrom
zhassan-aws:unimplemented

Conversation

@zhassan-aws
Copy link
Contributor

@zhassan-aws zhassan-aws commented Apr 15, 2022

Description of changes:

Currently, codegen_place returns a ProjectedPlace. For projections that are currently not supported, Kani panics since it's not possible to return a codegen_unimplemented expression as a ProjectedPlace. This PR changes the return type of codegen_place to a Result<ProjectedPlace, Err(...)> so that it can return an error for those cases that is then handled by the caller through calling codegen_unimplemented.

Resolved issues:

Part of #707.

Call-outs:

Testing:

  • How is this change tested? A new test for sub-array binding was added that checks that Kani doesn't crash, and instead reports that the construct is not supported.

  • Is this a refactor change? Part of it is.

Checklist

  • Each commit message has a non-empty body, explaining why the change was made
  • Methods or procedures are documented
  • Regression or unit tests are included, or existing tests cover the modified code
  • My PR is restricted to a single feature or bugfix

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.

… possibility of an error due to unsupported operations
@zhassan-aws zhassan-aws requested a review from a team as a code owner April 15, 2022 22:01
Comment on lines +588 to +590
/// A convenience macro that unwraps a `Result<ProjectPlace<'tcx>,
/// Err<UnimplementedData>` if it is Ok and returns an `codegen_unimplemented`
/// expression otherwise
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quick question: why macro and not function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this to have minimal changes on the caller side, it has to do a return, which cannot be done using a function (since it will return from that function, and not from the caller function). I hope the explanation is not too confusing.

Comment on lines +588 to +590
/// A convenience macro that unwraps a `Result<ProjectPlace<'tcx>,
/// Err<UnimplementedData>` if it is Ok and returns an `codegen_unimplemented`
/// expression otherwise
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quick question: why macro and not function?

Copy link
Contributor

@danielsn danielsn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like the general idea, but we need a better name for the macro

// https://rust-lang.github.io/rfcs/2359-subslice-pattern-syntax.html
match before.mir_typ().kind() {
ty::Array(..) => unimplemented!(),
ty::Array(ty, len) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a separate PR? Or change the title of this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to do in a separate PR. I took it out (along with the expected test that was added).

/// Err<UnimplementedData>` if it is Ok and returns an `codegen_unimplemented`
/// expression otherwise
#[macro_export]
macro_rules! unwrap_or_codegen_unimplemented {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This macro affects control flow where it is called; we should make sure to call that our clearly in the name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added return in the macro name: unwrap_or_return_codegen_unimplemented. Let me know if you have other suggestions.


/// Same as the above macro, but returns a goto program `Stmt` instead
#[macro_export]
macro_rules! unwrap_or_codegen_unimplemented_stmt {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, call out that this returns

e.as_stmt(Location::none())
} else {
self.codegen_place(&p).goto_expr.assign(e, Location::none())
unwrap_or_codegen_unimplemented_stmt!(self, self.codegen_place(&p))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to avoid repeating self, self.codegen_place

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had the same thought, but couldn't figure out a way to do it. I initially tried not passing self in, and just calling it from inside the macro, but that didn't work due to macro hygiene: https://stackoverflow.com/a/44124477.

@celinval
Copy link
Contributor

It looks good to me.

Can you please check what kind of error the user will get when we fail to generate a projection Expr that is used to generate other expressions? For example, when the projection is on an assignment like this:

let wrong.projection = value;

Thanks!

@danielsn danielsn dismissed their stale review April 19, 2022 01:44

Requested changes made

@danielsn
Copy link
Contributor

LGTM module @celinval comment

@zhassan-aws
Copy link
Contributor Author

Can you please check what kind of error the user will get when we fail to generate a projection Expr that is used to generate other expressions?

I used the following small program as an example:

#[kani::proof]
fn main() {
    let mut x = 5;
    let y = &mut x;
    *y = 9;
    assert!(x == 9);
}

and replaced the implementation of ProjectionElem::Deref in

by

                Err(UnimplementedData {
                    operation: "deref".to_string(),
                    bug_url: "".to_string(),
                    goto_type: self.codegen_ty(inner_mir_typ).to_pointer(),
                    loc: Location::None,

With that, Kani reported a single failure:

RESULTS:
Check 1: unsupported_construct.1
         - Status: FAILURE
         - Description: "deref is not currently supported by Kani. Please post your example at "

Check 2: main.assertion.1
         - Status: UNDETERMINED
         - Description: "assertion failed: x == 9"
         - Location: deref.rs:6:5 in function main


SUMMARY: 
 ** 1 of 2 failed (1 undetermined)
Failed Checks: deref is not currently supported by Kani. Please post your example at 

VERIFICATION:- FAILED

** WARNING: A Rust construct that is not currently supported by Kani was found to be reachable. Check the results for more details.

and neither Kani nor CBMC produced any other warnings/errors. The --gen-c output also indicates that the assignment to *y was completed omitted:

// file /home/ubuntu/examples/deref.rs line 2 column 1 function main
struct Unit main(void)
{
  struct Unit var_0;
  int x;
  int *y;
  struct Unit var_3;
  _Bool var_4;
  int var_5;

bb0:
  ;
  x = 5;
  y = &x;
  /* deref is not currently supported by Kani. Please post your example at  */
  assert(0);
  __CPROVER_assume(0);
  nondet_0();
  var_5 = x;
  var_4 = var_5 == 9;

This is because the callers to codegen_place will not proceed with performing the assignment if it returned Err.

Copy link
Contributor

@celinval celinval left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for checking!

@zhassan-aws zhassan-aws merged commit c3d41b9 into model-checking:main Apr 19, 2022
@zhassan-aws zhassan-aws deleted the unimplemented branch April 19, 2022 16:47
tedinski pushed a commit to tedinski/rmc that referenced this pull request Apr 26, 2022
tedinski pushed a commit that referenced this pull request Apr 27, 2022
… possibility of an error due to unsupported operations (#1057)
celinval added a commit to celinval/kani-dev that referenced this pull request May 17, 2022
We should probably turn this into an assert and revert the logic added
by model-checking#1057. But this is a much
larger change that I prefer creating a separate PR for.
celinval added a commit that referenced this pull request May 20, 2022
* Fix how we handle niche optimization with ZST

The compiler uses niche optimization when there is only one variant that
contains nonzero sized fields. This variant is represented as the
dataful variant. However, other variants may have one or more ZST fields
that can be deconstructed and referenced in the code.

Before this change, we were not generating code for them and it generate
type mismatch issues when the user tried to access them.

This change ensures that we represent all variants that have any field,
so their access is valid.

* Enable debug assert inside projection mismatch

We should probably turn this into an assert and revert the logic added
by #1057. But this is a much
larger change that I prefer creating a separate PR for.

Co-authored-by: Zyad Hassan <88045115+zhassan-aws@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants