mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #6507 from ethereum/smt_address_members
[SMTChecker] Address members
This commit is contained in:
@@ -28,14 +28,58 @@ EncodingContext::EncodingContext(SolverInterface& _solver):
|
||||
m_solver(_solver),
|
||||
m_thisAddress(make_unique<SymbolicAddressVariable>("this", m_solver))
|
||||
{
|
||||
auto sort = make_shared<smt::ArraySort>(
|
||||
make_shared<smt::Sort>(smt::Kind::Int),
|
||||
make_shared<smt::Sort>(smt::Kind::Int)
|
||||
);
|
||||
m_balances = make_unique<SymbolicVariable>(sort, "balances", m_solver);
|
||||
}
|
||||
|
||||
void EncodingContext::reset()
|
||||
{
|
||||
m_thisAddress->increaseIndex();
|
||||
m_balances->increaseIndex();
|
||||
}
|
||||
|
||||
smt::Expression EncodingContext::thisAddress()
|
||||
{
|
||||
return m_thisAddress->currentValue();
|
||||
}
|
||||
|
||||
smt::Expression EncodingContext::balance()
|
||||
{
|
||||
return balance(m_thisAddress->currentValue());
|
||||
}
|
||||
|
||||
smt::Expression EncodingContext::balance(smt::Expression _address)
|
||||
{
|
||||
return smt::Expression::select(m_balances->currentValue(), move(_address));
|
||||
}
|
||||
|
||||
void EncodingContext::transfer(smt::Expression _from, smt::Expression _to, smt::Expression _value)
|
||||
{
|
||||
unsigned indexBefore = m_balances->index();
|
||||
addBalance(_from, 0 - _value);
|
||||
addBalance(_to, move(_value));
|
||||
unsigned indexAfter = m_balances->index();
|
||||
solAssert(indexAfter > indexBefore, "");
|
||||
m_balances->increaseIndex();
|
||||
/// Do not apply the transfer operation if _from == _to.
|
||||
auto newBalances = smt::Expression::ite(
|
||||
move(_from) == move(_to),
|
||||
m_balances->valueAtIndex(indexBefore),
|
||||
m_balances->valueAtIndex(indexAfter)
|
||||
);
|
||||
m_solver.addAssertion(m_balances->currentValue() == newBalances);
|
||||
}
|
||||
|
||||
void EncodingContext::addBalance(smt::Expression _address, smt::Expression _value)
|
||||
{
|
||||
auto newBalances = smt::Expression::store(
|
||||
m_balances->currentValue(),
|
||||
_address,
|
||||
balance(_address) + move(_value)
|
||||
);
|
||||
m_balances->increaseIndex();
|
||||
m_solver.addAssertion(newBalances == m_balances->currentValue());
|
||||
}
|
||||
|
||||
@@ -41,12 +41,24 @@ public:
|
||||
/// Value of `this` address.
|
||||
smt::Expression thisAddress();
|
||||
|
||||
/// @returns the symbolic balance of address `this`.
|
||||
smt::Expression balance();
|
||||
/// @returns the symbolic balance of an address.
|
||||
smt::Expression balance(smt::Expression _address);
|
||||
/// Transfer _value from _from to _to.
|
||||
void transfer(smt::Expression _from, smt::Expression _to, smt::Expression _value);
|
||||
|
||||
private:
|
||||
/// Adds _value to _account's balance.
|
||||
void addBalance(smt::Expression _account, smt::Expression _value);
|
||||
|
||||
SolverInterface& m_solver;
|
||||
|
||||
/// Symbolic `this` address.
|
||||
std::unique_ptr<SymbolicAddressVariable> m_thisAddress;
|
||||
|
||||
/// Symbolic balances.
|
||||
std::unique_ptr<SymbolicVariable> m_balances;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ bool SMTChecker::visit(FunctionDefinition const& _function)
|
||||
if (isRootFunction())
|
||||
{
|
||||
m_interface->reset();
|
||||
m_context.reset();
|
||||
m_pathConditions.clear();
|
||||
m_callStack.clear();
|
||||
m_expressions.clear();
|
||||
@@ -609,6 +610,12 @@ void SMTChecker::endVisit(FunctionCall const& _funCall)
|
||||
popCallStack();
|
||||
break;
|
||||
case FunctionType::Kind::External:
|
||||
case FunctionType::Kind::DelegateCall:
|
||||
case FunctionType::Kind::BareCall:
|
||||
case FunctionType::Kind::BareCallCode:
|
||||
case FunctionType::Kind::BareDelegateCall:
|
||||
case FunctionType::Kind::BareStaticCall:
|
||||
case FunctionType::Kind::Creation:
|
||||
m_externalFunctionCallHappened = true;
|
||||
resetStateVariables();
|
||||
resetStorageReferences();
|
||||
@@ -622,6 +629,22 @@ void SMTChecker::endVisit(FunctionCall const& _funCall)
|
||||
case FunctionType::Kind::MulMod:
|
||||
abstractFunctionCall(_funCall);
|
||||
break;
|
||||
case FunctionType::Kind::Send:
|
||||
case FunctionType::Kind::Transfer:
|
||||
{
|
||||
auto const& memberAccess = dynamic_cast<MemberAccess const&>(_funCall.expression());
|
||||
auto const& address = memberAccess.expression();
|
||||
auto const& value = args.at(0);
|
||||
solAssert(value, "");
|
||||
|
||||
smt::Expression thisBalance = m_context.balance();
|
||||
setSymbolicUnknownValue(thisBalance, TypeProvider::uint256(), *m_interface);
|
||||
checkCondition(thisBalance < expr(*value), _funCall.location(), "Insufficient funds", "address(this).balance", &thisBalance);
|
||||
|
||||
m_context.transfer(m_context.thisAddress(), expr(address), expr(*value));
|
||||
createExpr(_funCall);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
m_errorReporter.warning(
|
||||
_funCall.location(),
|
||||
@@ -874,6 +897,17 @@ bool SMTChecker::visit(MemberAccess const& _memberAccess)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (exprType->category() == Type::Category::Address)
|
||||
{
|
||||
_memberAccess.expression().accept(*this);
|
||||
if (_memberAccess.memberName() == "balance")
|
||||
{
|
||||
defineExpr(_memberAccess, m_context.balance(expr(_memberAccess.expression())));
|
||||
setSymbolicUnknownValue(*m_expressions[&_memberAccess], *m_interface);
|
||||
m_uninterpretedTerms.insert(&_memberAccess);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_errorReporter.warning(
|
||||
_memberAccess.location(),
|
||||
|
||||
@@ -286,6 +286,7 @@ private:
|
||||
std::unordered_map<Expression const*, std::shared_ptr<SymbolicVariable>> m_expressions;
|
||||
std::unordered_map<VariableDeclaration const*, std::shared_ptr<SymbolicVariable>> m_variables;
|
||||
std::unordered_map<std::string, std::shared_ptr<SymbolicVariable>> m_globalContext;
|
||||
|
||||
/// Stores the instances of an Uninterpreted Function applied to arguments.
|
||||
/// These may be direct application of UFs or Array index access.
|
||||
/// Used to retrieve models.
|
||||
|
||||
Reference in New Issue
Block a user