Skip to content

Conversation

@leonardoalt
Copy link

@leonardoalt leonardoalt commented May 28, 2021

Fixes #10787

Spacer already gives invariants for every predicate when the result of a query is unsat, that's the interpretation of each predicate.
If we take those expressions for our interface_* and nondet_interface_* predicates, we have respectively, contract invariants (over a state) and reentrancy properties (over a transition).
So what we do here is

  • collect the z3::expr that represents the invariants (a big conjunction)
  • translate that into smtutil::Expression
  • collect the contract invariants above
  • format them in an almost-Solidity way

Open questions:

  • How do we report the found invariants? Imo it doesn't make sense to report them as warnings. For the JSON output, we can have a new object, but what about CLI?
  • Should we report only contract invariants or the reentrancy invariants too? The latter has not obvious semantics, so maybe requires a different output, separated from the contract invariants.

TODO:

Future:
The expressions can of course be simplified to transform things like a * (- 1) into -a among others, but that should go into a different PR.

@mijovic
Copy link
Contributor

mijovic commented Jun 9, 2021

I checked most of the tests and they are looking good.
Open question is how to report invariants in CLI interface. Do we have any open issue about additional way of reporting things from compiler? I think I saw discussion about having notice instead of warning, but can't find it now...

I am reviewing implementation now

@leonardoalt
Copy link
Author

We only briefly talked in the chat, should talk about that in the design call today.

Copy link
Contributor

@mijovic mijovic left a comment

Choose a reason for hiding this comment

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

Only first small comments.
I am doing another turn now

@leonardoalt
Copy link
Author

Test blockchain_state/balance_receive_calls.sol has (:var 1) terms which should be taken care of.

@leonardoalt leonardoalt force-pushed the smt_report_invariants branch 2 times, most recently from e67ed7a to 8f1645b Compare October 4, 2021 18:22
@leonardoalt leonardoalt marked this pull request as ready for review October 5, 2021 13:48
@leonardoalt leonardoalt force-pushed the smt_report_invariants branch from 8f1645b to e2588a5 Compare October 5, 2021 13:48
@leonardoalt
Copy link
Author

This is now ready for review

@leonardoalt leonardoalt force-pushed the smt_report_invariants branch 2 times, most recently from 4a653bf to 41838a7 Compare October 6, 2021 12:07
(x <= 0)
Reentrancy property(ies) for model_checker_invariants_contract_reentrancy/input.sol:test:
(!(x <= 0) || (x' <= 0))
((!(x <= 0) || !(<errorCode> >= 3)) && (!(x <= 0) || (x' <= 0)))
Copy link
Contributor

Choose a reason for hiding this comment

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

What's errorCode?

Copy link
Author

@leonardoalt leonardoalt Oct 7, 2021

Choose a reason for hiding this comment

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

Yea maybe we need to either change that or explain it a bit more. Every verification target (assertion, out of bounds, etc) gets a unique non-zero errorCode starting at one. So if errorCode = 0, all good. If errorCode > 0, something failed, but we're not saying here exactly what failed. Do you have a suggestion for how to handle it?

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually what does !(errorCode >= 3) mean here? The failure is one of the three {assertion, out of bounds, ...}.

Maybe it would be nice to print a table of error codes. It would be even better if we can change !(<errorCode> >= 3) to just a list of possibilities.

Copy link
Author

Choose a reason for hiding this comment

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

No, the number is not per target type, it's per query, basically.

Copy link
Author

Choose a reason for hiding this comment

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

I think it would be better to leave it is as for the moment, and try to explain what it means, and adjust it later. I don't have a clear answer about what's best for this now, so I'd prefer not to stall this PR and do it after.

Copy link
Author

Choose a reason for hiding this comment

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

Hmm maybe listing all targets if errorCode is present is not too hard to do

Copy link
Author

Choose a reason for hiding this comment

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

Or this @hrkrshnn

@leonardoalt leonardoalt force-pushed the smt_report_invariants branch from 41838a7 to e55b71d Compare October 7, 2021 11:37
return type;

return _args.at(0) + "." + type;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm going to assume this function is correct :)

Copy link
Author

Choose a reason for hiding this comment

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

I can argue for its correctness in a call if you want, but yea, I think it's also not too bad if it's buggy, since this is non essential extra information.

(x <= 0)
Reentrancy property(ies) for model_checker_invariants_contract_reentrancy/input.sol:test:
(!(x <= 0) || (x' <= 0))
((!(x <= 0) || !(<errorCode> >= 3)) && (!(x <= 0) || (x' <= 0)))
Copy link
Contributor

Choose a reason for hiding this comment

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

Actually what does !(errorCode >= 3) mean here? The failure is one of the three {assertion, out of bounds, ...}.

Maybe it would be nice to print a table of error codes. It would be even better if we can change !(<errorCode> >= 3) to just a list of possibilities.


if (m_ignoreInv)
ranges::actions::remove_if(m_errorList, [](auto&& _error) {
return _error.errorId && _error.errorId->error != 1180;
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't it possible to avoid creating this in the first place?

Copy link
Author

Choose a reason for hiding this comment

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

Yea, probably better.

@leonardoalt leonardoalt force-pushed the smt_report_invariants branch 2 times, most recently from 4399bcb to b72aabf Compare October 13, 2021 14:51
@leonardoalt leonardoalt force-pushed the smt_report_invariants branch from 830576f to 428bab6 Compare October 13, 2021 17:37
@leonardoalt
Copy link
Author

@hrkrshnn I fixed the latest comments in new commits, will fixup those in the proper original commits when the PR is approved.

Copy link
Collaborator

@cameel cameel left a comment

Choose a reason for hiding this comment

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

I haven't reviewed all of it yet but so far I haven't found anything important. Just minor stuff.

Comment on lines 350 to 357
else if (kind == Z3_OP_INT2BV)
smtAssert(false, "");
return Expression::int2bv(arguments[0], _expr.get_sort().bv_size());
else if (kind == Z3_OP_BV2INT)
smtAssert(false, "");
// TODO manually wrap the result with a check whether the number
// is positive or negative somehow.
return Expression::bv2int(arguments[0]);
else if (kind == Z3_OP_EXTRACT)
return Expression("extract", {arguments[0]. arguments[1]}, arguments[0].sort);
Copy link
Collaborator

Choose a reason for hiding this comment

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

What about the number of arguments here? Can there be more than 1 or 2? I think we need asserts against that.

And for Z3_OP_EXTRACT, do sorts have to be the same?

Copy link
Author

Choose a reason for hiding this comment

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

Good point. Extract is actually quite complex since it creates a new function for bitvectors of different sizes, so I'm just gonna do the same as dt_accessor and use all arguments with that operator's name. We can give it some interpretation if we ever handle it properly on the way from z3 to our representation.

Copy link
Collaborator

Choose a reason for hiding this comment

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

ok. What about Z3_OP_BV2INT and Z3_OP_INT2BV though?

hrkrshnn
hrkrshnn previously approved these changes Oct 19, 2021
Copy link
Contributor

@hrkrshnn hrkrshnn left a comment

Choose a reason for hiding this comment

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

Looks good. We agreed that this can be more or less merged and the additional changes can be done in follow up PR. Probably missing fixups.

@leonardoalt
Copy link
Author

Fixed @cameel 's comments and fixedup the fixup commits into the original ones.

Agreed on a call with @hrkrshnn to report locations the same as warnings in a different PR.

@cameel
Copy link
Collaborator

cameel commented Oct 19, 2021

Unfortunately I did not manage to finish the review today but so far I did not find anything that would look like an actual problem so if @hrkrshnn approves then I guess it should be fine to merge it.

@leonardoalt leonardoalt force-pushed the smt_report_invariants branch from f193e76 to ac8bf8c Compare October 21, 2021 19:00
@leonardoalt
Copy link
Author

@hrkrshnn merge merge?

@leonardoalt leonardoalt force-pushed the smt_report_invariants branch from ac8bf8c to 902a2e2 Compare October 26, 2021 09:31
@hrkrshnn hrkrshnn merged commit 401dd43 into develop Oct 26, 2021
@hrkrshnn hrkrshnn deleted the smt_report_invariants branch October 26, 2021 10:41
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.

[SMTChecker] CHC report invariants for safe asserts

6 participants