mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7107 from ethereum/smt_chc_constructor_interface
[SMTChecker] Add CHC constructor/interface/error blocks
This commit is contained in:
commit
cbac3a4208
@ -65,6 +65,52 @@ bool CHC::visit(ContractDefinition const& _contract)
|
|||||||
if (!SMTEncoder::visit(_contract))
|
if (!SMTEncoder::visit(_contract))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
m_stateVariables = _contract.stateVariablesIncludingInherited();
|
||||||
|
|
||||||
|
for (auto const& var: m_stateVariables)
|
||||||
|
// SMT solvers do not support function types as arguments.
|
||||||
|
if (var->type()->category() == Type::Category::Function)
|
||||||
|
m_stateSorts.push_back(make_shared<smt::Sort>(smt::Kind::Int));
|
||||||
|
else
|
||||||
|
m_stateSorts.push_back(smt::smtSort(*var->type()));
|
||||||
|
|
||||||
|
string interfaceName = "interface_" + _contract.name() + "_" + to_string(_contract.id());
|
||||||
|
m_interfacePredicate = createBlock(interfaceSort(), interfaceName);
|
||||||
|
|
||||||
|
// TODO create static instances for Bool/Int sorts in SolverInterface.
|
||||||
|
auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool);
|
||||||
|
auto errorFunctionSort = make_shared<smt::FunctionSort>(
|
||||||
|
vector<smt::SortPointer>(),
|
||||||
|
boolSort
|
||||||
|
);
|
||||||
|
m_errorPredicate = createBlock(errorFunctionSort, "error");
|
||||||
|
|
||||||
|
// If the contract has a constructor it is handled as a function.
|
||||||
|
// Otherwise we zero-initialize all state vars.
|
||||||
|
// TODO take into account state vars init values.
|
||||||
|
if (!_contract.constructor())
|
||||||
|
{
|
||||||
|
string constructorName = "constructor_" + _contract.name() + "_" + to_string(_contract.id());
|
||||||
|
m_constructorPredicate = createBlock(constructorSort(), constructorName);
|
||||||
|
|
||||||
|
for (auto const& var: m_stateVariables)
|
||||||
|
{
|
||||||
|
auto const& symbVar = m_context.variable(*var);
|
||||||
|
symbVar->increaseIndex();
|
||||||
|
m_interface->declareVariable(symbVar->currentName(), *symbVar->sort());
|
||||||
|
m_context.setZeroValue(*symbVar);
|
||||||
|
}
|
||||||
|
|
||||||
|
smt::Expression constructorAppl = (*m_constructorPredicate)({});
|
||||||
|
m_interface->addRule(constructorAppl, constructorName);
|
||||||
|
|
||||||
|
smt::Expression constructorInterface = smt::Expression::implies(
|
||||||
|
constructorAppl && m_context.assertions(),
|
||||||
|
interface()
|
||||||
|
);
|
||||||
|
m_interface->addRule(constructorInterface, constructorName + "_to_" + interfaceName);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +119,11 @@ void CHC::endVisit(ContractDefinition const& _contract)
|
|||||||
if (!shouldVisit(_contract))
|
if (!shouldVisit(_contract))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
auto errorAppl = (*m_errorPredicate)({});
|
||||||
|
for (auto const& target: m_verificationTargets)
|
||||||
|
if (query(errorAppl, target->location()))
|
||||||
|
m_safeAssertions.insert(target);
|
||||||
|
|
||||||
SMTEncoder::endVisit(_contract);
|
SMTEncoder::endVisit(_contract);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +182,8 @@ void CHC::visitAssert(FunctionCall const&)
|
|||||||
|
|
||||||
void CHC::reset()
|
void CHC::reset()
|
||||||
{
|
{
|
||||||
|
m_stateSorts.clear();
|
||||||
|
m_stateVariables.clear();
|
||||||
m_verificationTargets.clear();
|
m_verificationTargets.clear();
|
||||||
m_safeAssertions.clear();
|
m_safeAssertions.clear();
|
||||||
}
|
}
|
||||||
@ -155,6 +208,71 @@ bool CHC::shouldVisit(FunctionDefinition const& _function) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
smt::SortPointer CHC::constructorSort()
|
||||||
|
{
|
||||||
|
solAssert(m_currentContract, "");
|
||||||
|
auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool);
|
||||||
|
if (!m_currentContract->constructor())
|
||||||
|
return make_shared<smt::FunctionSort>(vector<smt::SortPointer>{}, boolSort);
|
||||||
|
return functionSort(*m_currentContract->constructor());
|
||||||
|
}
|
||||||
|
|
||||||
|
smt::SortPointer CHC::interfaceSort()
|
||||||
|
{
|
||||||
|
auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool);
|
||||||
|
return make_shared<smt::FunctionSort>(
|
||||||
|
m_stateSorts,
|
||||||
|
boolSort
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
smt::SortPointer CHC::functionSort(FunctionDefinition const& _function)
|
||||||
|
{
|
||||||
|
auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool);
|
||||||
|
auto const& funType = dynamic_cast<FunctionType const&>(*_function.type());
|
||||||
|
return make_shared<smt::FunctionSort>(
|
||||||
|
smt::smtSort(funType.parameterTypes()),
|
||||||
|
boolSort
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<smt::SymbolicFunctionVariable> CHC::createBlock(smt::SortPointer _sort, string const& _name)
|
||||||
|
{
|
||||||
|
auto block = make_unique<smt::SymbolicFunctionVariable>(
|
||||||
|
_sort,
|
||||||
|
_name,
|
||||||
|
m_context
|
||||||
|
);
|
||||||
|
m_interface->registerRelation(block->currentValue());
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
smt::Expression CHC::constructor()
|
||||||
|
{
|
||||||
|
solAssert(m_currentContract, "");
|
||||||
|
|
||||||
|
if (!m_currentContract->constructor())
|
||||||
|
return (*m_constructorPredicate)({});
|
||||||
|
|
||||||
|
vector<smt::Expression> paramExprs;
|
||||||
|
for (auto const& var: m_currentContract->constructor()->parameters())
|
||||||
|
paramExprs.push_back(m_context.variable(*var)->currentValue());
|
||||||
|
return (*m_constructorPredicate)(paramExprs);
|
||||||
|
}
|
||||||
|
|
||||||
|
smt::Expression CHC::interface()
|
||||||
|
{
|
||||||
|
vector<smt::Expression> paramExprs;
|
||||||
|
for (auto const& var: m_stateVariables)
|
||||||
|
paramExprs.push_back(m_context.variable(*var)->currentValue());
|
||||||
|
return (*m_interfacePredicate)(paramExprs);
|
||||||
|
}
|
||||||
|
|
||||||
|
smt::Expression CHC::error()
|
||||||
|
{
|
||||||
|
return (*m_errorPredicate)({});
|
||||||
|
}
|
||||||
|
|
||||||
bool CHC::query(smt::Expression const& _query, langutil::SourceLocation const& _location)
|
bool CHC::query(smt::Expression const& _query, langutil::SourceLocation const& _location)
|
||||||
{
|
{
|
||||||
smt::CheckResult result;
|
smt::CheckResult result;
|
||||||
|
@ -70,12 +70,57 @@ private:
|
|||||||
bool shouldVisit(FunctionDefinition const& _function) const;
|
bool shouldVisit(FunctionDefinition const& _function) const;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
/// Sort helpers.
|
||||||
|
//@{
|
||||||
|
smt::SortPointer constructorSort();
|
||||||
|
smt::SortPointer interfaceSort();
|
||||||
|
smt::SortPointer functionSort(FunctionDefinition const& _function);
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/// Predicate helpers.
|
||||||
|
//@{
|
||||||
|
/// @returns a new block of given _sort and _name.
|
||||||
|
std::unique_ptr<smt::SymbolicFunctionVariable> createBlock(smt::SortPointer _sort, std::string const& _name);
|
||||||
|
|
||||||
|
/// Constructor predicate over current variables.
|
||||||
|
smt::Expression constructor();
|
||||||
|
/// Interface predicate over current variables.
|
||||||
|
smt::Expression interface();
|
||||||
|
/// Error predicate over current variables.
|
||||||
|
smt::Expression error();
|
||||||
|
//@}
|
||||||
|
|
||||||
/// Solver related.
|
/// Solver related.
|
||||||
//@{
|
//@{
|
||||||
/// @returns true if query is unsatisfiable (safe).
|
/// @returns true if query is unsatisfiable (safe).
|
||||||
bool query(smt::Expression const& _query, langutil::SourceLocation const& _location);
|
bool query(smt::Expression const& _query, langutil::SourceLocation const& _location);
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
/// Predicates.
|
||||||
|
//@{
|
||||||
|
/// Constructor predicate.
|
||||||
|
/// Default constructor sets state vars to 0.
|
||||||
|
std::unique_ptr<smt::SymbolicVariable> m_constructorPredicate;
|
||||||
|
|
||||||
|
/// Artificial Interface predicate.
|
||||||
|
/// Single entry block for all functions.
|
||||||
|
std::unique_ptr<smt::SymbolicVariable> m_interfacePredicate;
|
||||||
|
|
||||||
|
/// Artificial Error predicate.
|
||||||
|
/// Single error block for all assertions.
|
||||||
|
std::unique_ptr<smt::SymbolicVariable> m_errorPredicate;
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/// Variables.
|
||||||
|
//@{
|
||||||
|
/// State variables sorts.
|
||||||
|
/// Used by all predicates.
|
||||||
|
std::vector<smt::SortPointer> m_stateSorts;
|
||||||
|
/// State variables.
|
||||||
|
/// Used to create all predicates.
|
||||||
|
std::vector<VariableDeclaration const*> m_stateVariables;
|
||||||
|
//@}
|
||||||
|
|
||||||
/// Verification targets.
|
/// Verification targets.
|
||||||
//@{
|
//@{
|
||||||
std::vector<Expression const*> m_verificationTargets;
|
std::vector<Expression const*> m_verificationTargets;
|
||||||
|
@ -40,6 +40,7 @@ bool SMTEncoder::visit(ContractDefinition const& _contract)
|
|||||||
m_currentContract = &_contract;
|
m_currentContract = &_contract;
|
||||||
|
|
||||||
initializeStateVariables(_contract);
|
initializeStateVariables(_contract);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user