mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge commit 'a7d481fb9' into develop_060
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
#include <libsolidity/formal/SymbolicTypes.h>
|
||||
|
||||
#include <boost/range/adaptors.hpp>
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
@@ -39,11 +40,28 @@ bool SMTEncoder::visit(ContractDefinition const& _contract)
|
||||
solAssert(m_currentContract, "");
|
||||
|
||||
for (auto const& node: _contract.subNodes())
|
||||
if (!dynamic_pointer_cast<FunctionDefinition>(node))
|
||||
if (
|
||||
!dynamic_pointer_cast<FunctionDefinition>(node) &&
|
||||
!dynamic_pointer_cast<VariableDeclaration>(node)
|
||||
)
|
||||
node->accept(*this);
|
||||
|
||||
vector<FunctionDefinition const*> resolvedFunctions = _contract.definedFunctions();
|
||||
for (auto const& base: _contract.annotation().linearizedBaseContracts)
|
||||
{
|
||||
// Look for all the constructor invocations bottom up.
|
||||
if (auto const& constructor = base->constructor())
|
||||
for (auto const& invocation: constructor->modifiers())
|
||||
{
|
||||
auto refDecl = invocation->name()->annotation().referencedDeclaration;
|
||||
if (auto const& baseContract = dynamic_cast<ContractDefinition const*>(refDecl))
|
||||
{
|
||||
solAssert(!m_baseConstructorCalls.count(baseContract), "");
|
||||
m_baseConstructorCalls[baseContract] = invocation.get();
|
||||
}
|
||||
}
|
||||
|
||||
// Check for function overrides.
|
||||
for (auto const& baseFunction: base->definedFunctions())
|
||||
{
|
||||
if (baseFunction->isConstructor())
|
||||
@@ -63,9 +81,18 @@ bool SMTEncoder::visit(ContractDefinition const& _contract)
|
||||
if (!overridden)
|
||||
resolvedFunctions.push_back(baseFunction);
|
||||
}
|
||||
}
|
||||
|
||||
// Functions are visited first since they might be used
|
||||
// for state variable initialization which is part of
|
||||
// the constructor.
|
||||
// Constructors are visited as part of the constructor
|
||||
// hierarchy inlining.
|
||||
for (auto const& function: resolvedFunctions)
|
||||
function->accept(*this);
|
||||
if (!function->isConstructor())
|
||||
function->accept(*this);
|
||||
|
||||
// Constructors need to be handled by the engines separately.
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -74,13 +101,16 @@ void SMTEncoder::endVisit(ContractDefinition const& _contract)
|
||||
{
|
||||
m_context.resetAllVariables();
|
||||
|
||||
m_baseConstructorCalls.clear();
|
||||
|
||||
solAssert(m_currentContract == &_contract, "");
|
||||
m_currentContract = nullptr;
|
||||
}
|
||||
|
||||
void SMTEncoder::endVisit(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
if (_varDecl.isLocalVariable() && _varDecl.type()->isValueType() &&_varDecl.value())
|
||||
// State variables are handled by the constructor.
|
||||
if (_varDecl.isLocalVariable() &&_varDecl.value())
|
||||
assignment(_varDecl, *_varDecl.value());
|
||||
}
|
||||
|
||||
@@ -91,25 +121,22 @@ bool SMTEncoder::visit(ModifierDefinition const&)
|
||||
|
||||
bool SMTEncoder::visit(FunctionDefinition const& _function)
|
||||
{
|
||||
// Not visited by a function call
|
||||
if (m_callStack.empty())
|
||||
initFunction(_function);
|
||||
|
||||
m_modifierDepthStack.push_back(-1);
|
||||
|
||||
if (_function.isConstructor())
|
||||
{
|
||||
m_errorReporter.warning(
|
||||
_function.location(),
|
||||
"Assertion checker does not yet support constructors."
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
_function.parameterList().accept(*this);
|
||||
if (_function.returnParameterList())
|
||||
_function.returnParameterList()->accept(*this);
|
||||
visitFunctionOrModifier();
|
||||
}
|
||||
inlineConstructorHierarchy(dynamic_cast<ContractDefinition const&>(*_function.scope()));
|
||||
|
||||
// Base constructors' parameters should be set by explicit calls,
|
||||
// but the most derived one needs to be initialized.
|
||||
if (_function.scope() == m_currentContract)
|
||||
initializeLocalVariables(_function);
|
||||
|
||||
_function.parameterList().accept(*this);
|
||||
if (_function.returnParameterList())
|
||||
_function.returnParameterList()->accept(*this);
|
||||
|
||||
visitFunctionOrModifier();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -131,27 +158,87 @@ void SMTEncoder::visitFunctionOrModifier()
|
||||
solAssert(m_modifierDepthStack.back() < int(function.modifiers().size()), "");
|
||||
ASTPointer<ModifierInvocation> const& modifierInvocation = function.modifiers()[m_modifierDepthStack.back()];
|
||||
solAssert(modifierInvocation, "");
|
||||
modifierInvocation->accept(*this);
|
||||
auto const& modifierDef = dynamic_cast<ModifierDefinition const&>(
|
||||
*modifierInvocation->name()->annotation().referencedDeclaration
|
||||
);
|
||||
vector<smt::Expression> modifierArgsExpr;
|
||||
if (auto const* arguments = modifierInvocation->arguments())
|
||||
{
|
||||
auto const& modifierParams = modifierDef.parameters();
|
||||
solAssert(modifierParams.size() == arguments->size(), "");
|
||||
for (unsigned i = 0; i < arguments->size(); ++i)
|
||||
modifierArgsExpr.push_back(expr(*arguments->at(i), modifierParams.at(i)->type()));
|
||||
}
|
||||
initializeFunctionCallParameters(modifierDef, modifierArgsExpr);
|
||||
pushCallStack({&modifierDef, modifierInvocation.get()});
|
||||
modifierDef.body().accept(*this);
|
||||
popCallStack();
|
||||
auto refDecl = modifierInvocation->name()->annotation().referencedDeclaration;
|
||||
if (dynamic_cast<ContractDefinition const*>(refDecl))
|
||||
visitFunctionOrModifier();
|
||||
else if (auto modifierDef = dynamic_cast<ModifierDefinition const*>(refDecl))
|
||||
inlineModifierInvocation(modifierInvocation.get(), modifierDef);
|
||||
else
|
||||
solAssert(false, "");
|
||||
}
|
||||
|
||||
--m_modifierDepthStack.back();
|
||||
}
|
||||
|
||||
void SMTEncoder::inlineModifierInvocation(ModifierInvocation const* _invocation, CallableDeclaration const* _definition)
|
||||
{
|
||||
solAssert(_invocation, "");
|
||||
_invocation->accept(*this);
|
||||
|
||||
vector<smt::Expression> args;
|
||||
if (auto const* arguments = _invocation->arguments())
|
||||
{
|
||||
auto const& modifierParams = _definition->parameters();
|
||||
solAssert(modifierParams.size() == arguments->size(), "");
|
||||
for (unsigned i = 0; i < arguments->size(); ++i)
|
||||
args.push_back(expr(*arguments->at(i), modifierParams.at(i)->type()));
|
||||
}
|
||||
|
||||
initializeFunctionCallParameters(*_definition, args);
|
||||
|
||||
pushCallStack({_definition, _invocation});
|
||||
if (auto modifier = dynamic_cast<ModifierDefinition const*>(_definition))
|
||||
{
|
||||
modifier->body().accept(*this);
|
||||
popCallStack();
|
||||
}
|
||||
else if (auto function = dynamic_cast<FunctionDefinition const*>(_definition))
|
||||
{
|
||||
if (function->isImplemented())
|
||||
function->accept(*this);
|
||||
// Functions are popped from the callstack in endVisit(FunctionDefinition)
|
||||
}
|
||||
}
|
||||
|
||||
void SMTEncoder::inlineConstructorHierarchy(ContractDefinition const& _contract)
|
||||
{
|
||||
auto const& hierarchy = m_currentContract->annotation().linearizedBaseContracts;
|
||||
auto it = find(begin(hierarchy), end(hierarchy), &_contract);
|
||||
solAssert(it != end(hierarchy), "");
|
||||
|
||||
auto nextBase = it + 1;
|
||||
// Initialize the base contracts here as long as their constructors are implicit,
|
||||
// stop when the first explicit constructor is found.
|
||||
while (nextBase != end(hierarchy))
|
||||
{
|
||||
if (auto baseConstructor = (*nextBase)->constructor())
|
||||
{
|
||||
createLocalVariables(*baseConstructor);
|
||||
// If any subcontract explicitly called baseConstructor, use those arguments.
|
||||
if (m_baseConstructorCalls.count(*nextBase))
|
||||
inlineModifierInvocation(m_baseConstructorCalls.at(*nextBase), baseConstructor);
|
||||
else if (baseConstructor->isImplemented())
|
||||
{
|
||||
// The first constructor found is handled like a function
|
||||
// and its pushed into the callstack there.
|
||||
// This if avoids duplication in the callstack.
|
||||
if (!m_callStack.empty())
|
||||
pushCallStack({baseConstructor, nullptr});
|
||||
baseConstructor->accept(*this);
|
||||
// popped by endVisit(FunctionDefinition)
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
initializeStateVariables(**nextBase);
|
||||
++nextBase;
|
||||
}
|
||||
}
|
||||
|
||||
initializeStateVariables(_contract);
|
||||
}
|
||||
|
||||
bool SMTEncoder::visit(PlaceholderStatement const&)
|
||||
{
|
||||
solAssert(!m_callStack.empty(), "");
|
||||
@@ -552,20 +639,25 @@ void SMTEncoder::initContract(ContractDefinition const& _contract)
|
||||
solAssert(m_currentContract == nullptr, "");
|
||||
m_currentContract = &_contract;
|
||||
|
||||
initializeStateVariables(_contract);
|
||||
m_context.reset();
|
||||
m_context.pushSolver();
|
||||
createStateVariables(_contract);
|
||||
clearIndices(m_currentContract, nullptr);
|
||||
}
|
||||
|
||||
void SMTEncoder::initFunction(FunctionDefinition const& _function)
|
||||
{
|
||||
solAssert(m_callStack.empty(), "");
|
||||
solAssert(m_currentContract, "");
|
||||
m_context.reset();
|
||||
m_context.pushSolver();
|
||||
m_pathConditions.clear();
|
||||
pushCallStack({&_function, nullptr});
|
||||
m_uninterpretedTerms.clear();
|
||||
resetStateVariables();
|
||||
initializeLocalVariables(_function);
|
||||
createStateVariables(*m_currentContract);
|
||||
createLocalVariables(_function);
|
||||
m_arrayAssignmentHappened = false;
|
||||
clearIndices(m_currentContract, &_function);
|
||||
}
|
||||
|
||||
void SMTEncoder::visitAssert(FunctionCall const& _funCall)
|
||||
@@ -808,11 +900,8 @@ void SMTEncoder::endVisit(IndexAccess const& _indexAccess)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_indexAccess.indexExpression())
|
||||
{
|
||||
solAssert(_indexAccess.annotation().type->category() == Type::Category::TypeType, "");
|
||||
if (_indexAccess.annotation().type->category() == Type::Category::TypeType)
|
||||
return;
|
||||
}
|
||||
|
||||
solAssert(array, "");
|
||||
defineExpr(_indexAccess, smt::Expression::select(
|
||||
@@ -1249,26 +1338,61 @@ void SMTEncoder::initializeFunctionCallParameters(CallableDeclaration const& _fu
|
||||
}
|
||||
}
|
||||
|
||||
void SMTEncoder::initializeStateVariables(ContractDefinition const& _contract)
|
||||
void SMTEncoder::createStateVariables(ContractDefinition const& _contract)
|
||||
{
|
||||
for (auto var: _contract.stateVariablesIncludingInherited())
|
||||
createVariable(*var);
|
||||
}
|
||||
|
||||
void SMTEncoder::initializeLocalVariables(FunctionDefinition const& _function)
|
||||
void SMTEncoder::initializeStateVariables(ContractDefinition const& _contract)
|
||||
{
|
||||
for (auto var: _contract.stateVariables())
|
||||
{
|
||||
solAssert(m_context.knownVariable(*var), "");
|
||||
m_context.setZeroValue(*var);
|
||||
}
|
||||
|
||||
for (auto var: _contract.stateVariables())
|
||||
if (var->value())
|
||||
{
|
||||
var->value()->accept(*this);
|
||||
assignment(*var, *var->value());
|
||||
}
|
||||
}
|
||||
|
||||
void SMTEncoder::createLocalVariables(FunctionDefinition const& _function)
|
||||
{
|
||||
for (auto const& variable: _function.localVariables())
|
||||
if (createVariable(*variable))
|
||||
m_context.setZeroValue(*variable);
|
||||
createVariable(*variable);
|
||||
|
||||
for (auto const& param: _function.parameters())
|
||||
if (createVariable(*param))
|
||||
m_context.setUnknownValue(*param);
|
||||
createVariable(*param);
|
||||
|
||||
if (_function.returnParameterList())
|
||||
for (auto const& retParam: _function.returnParameters())
|
||||
if (createVariable(*retParam))
|
||||
m_context.setZeroValue(*retParam);
|
||||
createVariable(*retParam);
|
||||
}
|
||||
|
||||
void SMTEncoder::initializeLocalVariables(FunctionDefinition const& _function)
|
||||
{
|
||||
for (auto const& variable: _function.localVariables())
|
||||
{
|
||||
solAssert(m_context.knownVariable(*variable), "");
|
||||
m_context.setZeroValue(*variable);
|
||||
}
|
||||
|
||||
for (auto const& param: _function.parameters())
|
||||
{
|
||||
solAssert(m_context.knownVariable(*param), "");
|
||||
m_context.setUnknownValue(*param);
|
||||
}
|
||||
|
||||
if (_function.returnParameterList())
|
||||
for (auto const& retParam: _function.returnParameters())
|
||||
{
|
||||
solAssert(m_context.knownVariable(*retParam), "");
|
||||
m_context.setZeroValue(*retParam);
|
||||
}
|
||||
}
|
||||
|
||||
void SMTEncoder::resetStateVariables()
|
||||
@@ -1448,6 +1572,20 @@ void SMTEncoder::resetVariableIndices(VariableIndices const& _indices)
|
||||
m_context.variable(*var.first)->index() = var.second;
|
||||
}
|
||||
|
||||
void SMTEncoder::clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function)
|
||||
{
|
||||
solAssert(_contract, "");
|
||||
for (auto var: _contract->stateVariablesIncludingInherited())
|
||||
m_context.variable(*var)->resetIndex();
|
||||
if (_function)
|
||||
{
|
||||
for (auto const& var: _function->parameters() + _function->returnParameters())
|
||||
m_context.variable(*var)->resetIndex();
|
||||
for (auto const& var: _function->localVariables())
|
||||
m_context.variable(*var)->resetIndex();
|
||||
}
|
||||
}
|
||||
|
||||
Expression const* SMTEncoder::leftmostBase(IndexAccess const& _indexAccess)
|
||||
{
|
||||
Expression const* base = &_indexAccess.baseExpression();
|
||||
|
||||
Reference in New Issue
Block a user