Skip to content

[SMTChecker] Support to integer and Bool storage vars #3947

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 3 commits into from
May 15, 2018
Merged

Conversation

leonardoalt
Copy link
Member

@leonardoalt leonardoalt commented Apr 19, 2018

The encoding isn't very different from local variables. In the beginning of every function the state vars are reset, meaning that their SSA index is increased and the new var is set to unknown.

Maybe we need more tests, not sure.

Added Changelog entry under 23 for now, will rebase later on.

m_interface->reset();
m_variables.clear();
m_variables.insert(m_stateVariables.begin(), m_stateVariables.end());
Copy link
Member Author

Choose a reason for hiding this comment

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

m_variables is mostly used in a way that works for both local and state vars, that's why I decided to have only one map (instead of this one and another m_stateVariables) and add the state vars to m_variables in the beginning of a function visit

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this can still be refactored a little better, for example having only a single map where the entries know when they have to be reset and how, but we can merge it like that for now.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this can still be refactored a little better, for example having only a single map where the entries know when they have to be reset and how, but we can merge it like that for now.

@@ -607,7 +615,8 @@ void SMTChecker::checkCondition(
message << " for:\n";
solAssert(values.size() == expressionNames.size(), "");
for (size_t i = 0; i < values.size(); ++i)
message << " " << expressionNames.at(i) << " = " << values.at(i) << "\n";
if (expressionsToEvaluate.at(i).name != values.at(i))
message << " " << expressionNames.at(i) << " = " << values.at(i) << "\n";
Copy link
Member Author

Choose a reason for hiding this comment

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

This if had to be added so that state variables that are not touched by a function don't appear in a counterexample, since they don't have a model. In that case, the solver returns the name of the SMT variable itself as the model. Right now this happens only for Bool. The reason is that when we set a Bool var to unknown, no constraint is added to the solver, therefore if the function doesn't do anything with this state var, it's just not there. Since integers have constraints for the unknown case, integer state variables will have a model even if they're not used.

So, we should choose one out of the following 3 cases for how counterexamples are shown:

  1. As it is in this PR: unused state integer vars get a model, Bools don't.
  2. Unused Bool state vars should have a model too. This case is probably simple to create, we just have to add the trivial constraint (or var (not var)) in the unknown case.
  3. No unused state vars should have models. This is more complicated and would require changes in the class VariableUsage or something similar

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's fine this way.

@@ -62,6 +62,8 @@ void SMTChecker::endVisit(VariableDeclaration const& _varDecl)
{
if (_varDecl.isLocalVariable() && _varDecl.type()->isValueType() &&_varDecl.value())
assignment(_varDecl, *_varDecl.value(), _varDecl.location());
else if (_varDecl.isStateVariable() && _varDecl.type()->isValueType())
Copy link
Contributor

Choose a reason for hiding this comment

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

This probably fails if variables are declared below functions. I think we have to manually register them.

Copy link
Member Author

Choose a reason for hiding this comment

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

True.. I read somewhere that state vars were visited before functions, but you're right.

@@ -62,6 +62,8 @@ void SMTChecker::endVisit(VariableDeclaration const& _varDecl)
{
if (_varDecl.isLocalVariable() && _varDecl.type()->isValueType() &&_varDecl.value())
Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, I think this was always wrong with variables like var (a, b) = f().

m_pathConditions.clear();
m_conditionalExecutionHappened = false;
initializeLocalVariables(_function);
resetStateVariables();
Copy link
Contributor

Choose a reason for hiding this comment

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

Above, we call m_interface->reset(), so is this really necessary?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's necessary to re-add the range constraints coming from types

else
{
solAssert(_varDecl.isStateVariable(), "");
m_stateVariables.emplace(&_varDecl, SSAVariable(_varDecl, *m_interface));
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we have this distinction in the first place? If we do not add the state variables to m_variables, they are not taken into account when unifying branches.

Copy link
Member Author

Choose a reason for hiding this comment

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

The distinction is because state vars are visited before functions, so we keep a single copy while visiting all the functions, and add them to m_variables in the beginning of each function

Copy link
Member Author

Choose a reason for hiding this comment

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

So, the thing about state vars being visited before functions: has to be done manually

Copy link
Contributor

@chriseth chriseth left a comment

Choose a reason for hiding this comment

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

m_variables do not include m_stateVariables. Because of that, a test for if(b) { a = 200; } assert(a == 200); should be incorrect if a is a state variable and b is an input.

@leonardoalt
Copy link
Member Author

m_stateVariables is included in m_variables when a function is visited, with the resets:
m_variables.insert(m_stateVariables.begin(), m_stateVariables.end());

@leonardoalt leonardoalt changed the title [SMTChecker] Support to integer and Bool storage vars [DO NOT MERGE][SMTChecker] Support to integer and Bool storage vars May 2, 2018
@leonardoalt leonardoalt changed the title [DO NOT MERGE][SMTChecker] Support to integer and Bool storage vars [SMTChecker] Support to integer and Bool storage vars May 2, 2018
@@ -33,7 +33,6 @@ VariableUsage::VariableUsage(ASTNode const& _node)
solAssert(declaration, "");
if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
if (
varDecl->isLocalVariable() &&
identifier->annotation().lValueRequested &&
Copy link
Contributor

Choose a reason for hiding this comment

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

This might not work correctly for tuple assignments, I created an issue for that: #4141

Copy link
Member Author

Choose a reason for hiding this comment

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

True, I wanted to check that after a similar comment from you

@@ -58,6 +58,19 @@ void SMTChecker::analyze(SourceUnit const& _source)
_source.accept(*this);
}

bool SMTChecker::visit(ContractDefinition const& _contract)
{
for (auto _var : _contract.stateVariables())
Copy link
Contributor

Choose a reason for hiding this comment

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

This does not include inherited state variables, so we have to be careful once we add inheritance.

chriseth
chriseth previously approved these changes May 15, 2018
chriseth
chriseth previously approved these changes May 15, 2018
@chriseth
Copy link
Contributor

Rebased and adjusted changelog entry.

@chriseth chriseth merged commit 63861aa into develop May 15, 2018
@axic axic deleted the smt_storage branch June 11, 2018 11:05
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.

2 participants