mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[SMTChecker] Clear state knowledge after external function calls
This commit is contained in:
parent
f8e9aed839
commit
7f8ceaadab
@ -7,6 +7,7 @@ Language Features:
|
||||
Compiler Features:
|
||||
* Control Flow Graph: Warn about unreachable code.
|
||||
* SMTChecker: Support basic typecasts without truncation.
|
||||
* SMTChecker: Support external function calls and erase all knowledge regarding storage variables and references.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
|
@ -418,6 +418,10 @@ void SMTChecker::endVisit(FunctionCall const& _funCall)
|
||||
case FunctionType::Kind::Internal:
|
||||
inlineFunctionCall(_funCall);
|
||||
break;
|
||||
case FunctionType::Kind::External:
|
||||
resetStateVariables();
|
||||
resetStorageReferences();
|
||||
break;
|
||||
case FunctionType::Kind::KECCAK256:
|
||||
case FunctionType::Kind::ECRecover:
|
||||
case FunctionType::Kind::SHA256:
|
||||
@ -1194,25 +1198,35 @@ void SMTChecker::removeLocalVariables()
|
||||
}
|
||||
}
|
||||
|
||||
void SMTChecker::resetVariable(VariableDeclaration const& _variable)
|
||||
{
|
||||
newValue(_variable);
|
||||
setUnknownValue(_variable);
|
||||
}
|
||||
|
||||
void SMTChecker::resetStateVariables()
|
||||
{
|
||||
for (auto const& variable: m_variables)
|
||||
{
|
||||
if (variable.first->isStateVariable())
|
||||
{
|
||||
newValue(*variable.first);
|
||||
setUnknownValue(*variable.first);
|
||||
}
|
||||
}
|
||||
resetVariables([&](VariableDeclaration const& _variable) { return _variable.isStateVariable(); });
|
||||
}
|
||||
|
||||
void SMTChecker::resetStorageReferences()
|
||||
{
|
||||
resetVariables([&](VariableDeclaration const& _variable) { return _variable.hasReferenceOrMappingType(); });
|
||||
}
|
||||
|
||||
void SMTChecker::resetVariables(vector<VariableDeclaration const*> _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);
|
||||
setUnknownValue(*decl);
|
||||
}
|
||||
if (_filter(*_variable.first))
|
||||
this->resetVariable(*_variable.first);
|
||||
});
|
||||
}
|
||||
|
||||
void SMTChecker::mergeVariables(vector<VariableDeclaration const*> const& _variables, smt::Expression const& _condition, VariableIndices const& _indicesEndTrue, VariableIndices const& _indicesEndFalse)
|
||||
|
@ -147,8 +147,11 @@ private:
|
||||
|
||||
void initializeLocalVariables(FunctionDefinition const& _function);
|
||||
void initializeFunctionCallParameters(FunctionDefinition const& _function, std::vector<smt::Expression> const& _callArgs);
|
||||
void resetVariable(VariableDeclaration const& _variable);
|
||||
void resetStateVariables();
|
||||
void resetStorageReferences();
|
||||
void resetVariables(std::vector<VariableDeclaration const*> _variables);
|
||||
void resetVariables(std::function<bool(VariableDeclaration const&)> const& _filter);
|
||||
/// Given two different branches and the touched variables,
|
||||
/// merge the touched variables into after-branch ite variables
|
||||
/// using the branch condition as guard.
|
||||
|
@ -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.
|
||||
|
@ -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
|
@ -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
|
@ -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
|
Loading…
Reference in New Issue
Block a user