Merge pull request #5718 from ethereum/smt_external_functions

[SMTChecker] Clear state knowledge after external function calls
This commit is contained in:
chriseth 2019-01-21 18:36:09 +01:00 committed by GitHub
commit 05b0d32e0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 93 additions and 12 deletions

View File

@ -7,6 +7,7 @@ Language Features:
Compiler Features: Compiler Features:
* Control Flow Graph: Warn about unreachable code. * Control Flow Graph: Warn about unreachable code.
* SMTChecker: Support basic typecasts without truncation. * SMTChecker: Support basic typecasts without truncation.
* SMTChecker: Support external function calls and erase all knowledge regarding storage variables and references.
Bugfixes: Bugfixes:

View File

@ -418,6 +418,10 @@ void SMTChecker::endVisit(FunctionCall const& _funCall)
case FunctionType::Kind::Internal: case FunctionType::Kind::Internal:
inlineFunctionCall(_funCall); inlineFunctionCall(_funCall);
break; break;
case FunctionType::Kind::External:
resetStateVariables();
resetStorageReferences();
break;
case FunctionType::Kind::KECCAK256: case FunctionType::Kind::KECCAK256:
case FunctionType::Kind::ECRecover: case FunctionType::Kind::ECRecover:
case FunctionType::Kind::SHA256: case FunctionType::Kind::SHA256:
@ -1194,25 +1198,35 @@ void SMTChecker::removeLocalVariables()
} }
} }
void SMTChecker::resetVariable(VariableDeclaration const& _variable)
{
newValue(_variable);
setUnknownValue(_variable);
}
void SMTChecker::resetStateVariables() void SMTChecker::resetStateVariables()
{ {
for (auto const& variable: m_variables) resetVariables([&](VariableDeclaration const& _variable) { return _variable.isStateVariable(); });
{ }
if (variable.first->isStateVariable())
{ void SMTChecker::resetStorageReferences()
newValue(*variable.first); {
setUnknownValue(*variable.first); resetVariables([&](VariableDeclaration const& _variable) { return _variable.hasReferenceOrMappingType(); });
}
}
} }
void SMTChecker::resetVariables(vector<VariableDeclaration const*> _variables) void SMTChecker::resetVariables(vector<VariableDeclaration const*> _variables)
{ {
for (auto const* decl: _variables) for (auto const* decl: _variables)
resetVariable(*decl);
}
void SMTChecker::resetVariables(function<bool(VariableDeclaration const&)> const& _filter)
{
for_each(begin(m_variables), end(m_variables), [&](auto _variable)
{ {
newValue(*decl); if (_filter(*_variable.first))
setUnknownValue(*decl); this->resetVariable(*_variable.first);
} });
} }
void SMTChecker::mergeVariables(vector<VariableDeclaration const*> const& _variables, smt::Expression const& _condition, VariableIndices const& _indicesEndTrue, VariableIndices const& _indicesEndFalse) void SMTChecker::mergeVariables(vector<VariableDeclaration const*> const& _variables, smt::Expression const& _condition, VariableIndices const& _indicesEndTrue, VariableIndices const& _indicesEndFalse)

View File

@ -147,8 +147,11 @@ private:
void initializeLocalVariables(FunctionDefinition const& _function); void initializeLocalVariables(FunctionDefinition const& _function);
void initializeFunctionCallParameters(FunctionDefinition const& _function, std::vector<smt::Expression> const& _callArgs); void initializeFunctionCallParameters(FunctionDefinition const& _function, std::vector<smt::Expression> const& _callArgs);
void resetVariable(VariableDeclaration const& _variable);
void resetStateVariables(); void resetStateVariables();
void resetStorageReferences();
void resetVariables(std::vector<VariableDeclaration const*> _variables); void resetVariables(std::vector<VariableDeclaration const*> _variables);
void resetVariables(std::function<bool(VariableDeclaration const&)> const& _filter);
/// Given two different branches and the touched variables, /// Given two different branches and the touched variables,
/// merge the touched variables into after-branch ite variables /// merge the touched variables into after-branch ite variables
/// using the branch condition as guard. /// using the branch condition as guard.

View File

@ -9,5 +9,4 @@ contract C {
} }
} }
// ---- // ----
// Warning: (99-107): Assertion checker does not yet implement this type of function call.
// Warning: (141-144): Assertion checker does not support recursive function calls. // Warning: (141-144): Assertion checker does not support recursive function calls.

View File

@ -0,0 +1,21 @@
pragma experimental SMTChecker;
contract D
{
function g(uint x) public;
}
contract C
{
uint x;
function f(uint y, D d) public {
require(x == y);
assert(x == y);
d.g(y);
// Storage knowledge is cleared after an external call.
assert(x == y);
}
}
// ----
// Warning: (119-122): Assertion checker does not yet support the type of this variable.
// Warning: (240-254): Assertion violation happens here

View File

@ -0,0 +1,21 @@
pragma experimental SMTChecker;
contract D
{
function g(uint x) public;
}
contract C
{
mapping (uint => uint) map;
function f(uint y, D d) public {
require(map[0] == map[1]);
assert(map[0] == map[1]);
d.g(y);
// Storage knowledge is cleared after an external call.
assert(map[0] == map[1]);
}
}
// ----
// Warning: (139-142): Assertion checker does not yet support the type of this variable.
// Warning: (280-304): Assertion violation happens here

View File

@ -0,0 +1,22 @@
pragma experimental SMTChecker;
contract D
{
function g(uint x) public;
}
contract C
{
mapping (uint => uint) storageMap;
function f(uint y, D d) public {
mapping (uint => uint) storage map = storageMap;
require(map[0] == map[1]);
assert(map[0] == map[1]);
d.g(y);
// Storage knowledge is cleared after an external call.
assert(map[0] == map[1]);
}
}
// ----
// Warning: (146-149): Assertion checker does not yet support the type of this variable.
// Warning: (338-362): Assertion violation happens here