mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #5718 from ethereum/smt_external_functions
[SMTChecker] Clear state knowledge after external function calls
This commit is contained in:
commit
05b0d32e0a
@ -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:
|
||||||
|
@ -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)
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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