-
Notifications
You must be signed in to change notification settings - Fork 6.1k
[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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,6 +58,19 @@ void SMTChecker::analyze(SourceUnit const& _source) | |
_source.accept(*this); | ||
} | ||
|
||
bool SMTChecker::visit(ContractDefinition const& _contract) | ||
{ | ||
for (auto _var : _contract.stateVariables()) | ||
if (_var->type()->isValueType()) | ||
createVariable(*_var); | ||
return true; | ||
} | ||
|
||
void SMTChecker::endVisit(ContractDefinition const&) | ||
{ | ||
m_stateVariables.clear(); | ||
} | ||
|
||
void SMTChecker::endVisit(VariableDeclaration const& _varDecl) | ||
{ | ||
if (_varDecl.isLocalVariable() && _varDecl.type()->isValueType() &&_varDecl.value()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, I think this was always wrong with variables like |
||
|
@@ -72,13 +85,13 @@ bool SMTChecker::visit(FunctionDefinition const& _function) | |
"Assertion checker does not yet support constructors and functions with modifiers." | ||
); | ||
m_currentFunction = &_function; | ||
// We only handle local variables, so we clear at the beginning of the function. | ||
// If we add storage variables, those should be cleared differently. | ||
m_interface->reset(); | ||
m_variables.clear(); | ||
m_variables.insert(m_stateVariables.begin(), m_stateVariables.end()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
m_pathConditions.clear(); | ||
m_loopExecutionHappened = false; | ||
initializeLocalVariables(_function); | ||
resetStateVariables(); | ||
return true; | ||
} | ||
|
||
|
@@ -586,6 +599,12 @@ void SMTChecker::checkCondition( | |
expressionsToEvaluate.emplace_back(currentValue(*var)); | ||
expressionNames.push_back(var->name()); | ||
} | ||
for (auto const& var: m_stateVariables) | ||
if (knownVariable(*var.first)) | ||
{ | ||
expressionsToEvaluate.emplace_back(currentValue(*var.first)); | ||
expressionNames.push_back(var.first->name()); | ||
} | ||
} | ||
smt::CheckResult result; | ||
vector<string> values; | ||
|
@@ -607,7 +626,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"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This So, we should choose one out of the following 3 cases for how counterexamples are shown:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's fine this way. |
||
} | ||
else | ||
message << "."; | ||
|
@@ -722,6 +742,15 @@ void SMTChecker::initializeLocalVariables(FunctionDefinition const& _function) | |
setZeroValue(*retParam); | ||
} | ||
|
||
void SMTChecker::resetStateVariables() | ||
{ | ||
for (auto const& variable: m_stateVariables) | ||
{ | ||
newValue(*variable.first); | ||
setUnknownValue(*variable.first); | ||
} | ||
} | ||
|
||
void SMTChecker::resetVariables(vector<Declaration const*> _variables) | ||
{ | ||
for (auto const* decl: _variables) | ||
|
@@ -752,7 +781,14 @@ bool SMTChecker::createVariable(VariableDeclaration const& _varDecl) | |
if (SSAVariable::isSupportedType(_varDecl.type()->category())) | ||
{ | ||
solAssert(m_variables.count(&_varDecl) == 0, ""); | ||
m_variables.emplace(&_varDecl, SSAVariable(_varDecl, *m_interface)); | ||
solAssert(m_stateVariables.count(&_varDecl) == 0, ""); | ||
if (_varDecl.isLocalVariable()) | ||
m_variables.emplace(&_varDecl, SSAVariable(_varDecl, *m_interface)); | ||
else | ||
{ | ||
solAssert(_varDecl.isStateVariable(), ""); | ||
m_stateVariables.emplace(&_varDecl, SSAVariable(_varDecl, *m_interface)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
} | ||
return true; | ||
} | ||
else | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, I wanted to check that after a similar comment from you |
||
varDecl->annotation().type->isValueType() | ||
) | ||
|
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.
This does not include inherited state variables, so we have to be careful once we add inheritance.