mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Refactor CHC sorts
This commit is contained in:
parent
5355e85639
commit
d87e15e2cd
@ -104,6 +104,8 @@ set(sources
|
|||||||
formal/ModelChecker.h
|
formal/ModelChecker.h
|
||||||
formal/Predicate.cpp
|
formal/Predicate.cpp
|
||||||
formal/Predicate.h
|
formal/Predicate.h
|
||||||
|
formal/PredicateSort.cpp
|
||||||
|
formal/PredicateSort.h
|
||||||
formal/SMTEncoder.cpp
|
formal/SMTEncoder.cpp
|
||||||
formal/SMTEncoder.h
|
formal/SMTEncoder.h
|
||||||
formal/SSAVariable.cpp
|
formal/SSAVariable.cpp
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <libsmtutil/Z3CHCInterface.h>
|
#include <libsmtutil/Z3CHCInterface.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <libsolidity/formal/PredicateSort.h>
|
||||||
#include <libsolidity/formal/SymbolicTypes.h>
|
#include <libsolidity/formal/SymbolicTypes.h>
|
||||||
|
|
||||||
#include <libsolidity/ast/TypeProvider.h>
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
@ -39,13 +40,14 @@ using namespace solidity::util;
|
|||||||
using namespace solidity::langutil;
|
using namespace solidity::langutil;
|
||||||
using namespace solidity::smtutil;
|
using namespace solidity::smtutil;
|
||||||
using namespace solidity::frontend;
|
using namespace solidity::frontend;
|
||||||
|
using namespace solidity::frontend::smt;
|
||||||
|
|
||||||
CHC::CHC(
|
CHC::CHC(
|
||||||
smt::EncodingContext& _context,
|
EncodingContext& _context,
|
||||||
ErrorReporter& _errorReporter,
|
ErrorReporter& _errorReporter,
|
||||||
[[maybe_unused]] map<util::h256, string> const& _smtlib2Responses,
|
[[maybe_unused]] map<util::h256, string> const& _smtlib2Responses,
|
||||||
[[maybe_unused]] ReadCallback::Callback const& _smtCallback,
|
[[maybe_unused]] ReadCallback::Callback const& _smtCallback,
|
||||||
smtutil::SMTSolverChoice _enabledSolvers
|
SMTSolverChoice _enabledSolvers
|
||||||
):
|
):
|
||||||
SMTEncoder(_context),
|
SMTEncoder(_context),
|
||||||
m_outerErrorReporter(_errorReporter),
|
m_outerErrorReporter(_errorReporter),
|
||||||
@ -56,7 +58,7 @@ CHC::CHC(
|
|||||||
usesZ3 = false;
|
usesZ3 = false;
|
||||||
#endif
|
#endif
|
||||||
if (!usesZ3)
|
if (!usesZ3)
|
||||||
m_interface = make_unique<smtutil::CHCSmtLib2Interface>(_smtlib2Responses, _smtCallback);
|
m_interface = make_unique<CHCSmtLib2Interface>(_smtlib2Responses, _smtCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHC::analyze(SourceUnit const& _source)
|
void CHC::analyze(SourceUnit const& _source)
|
||||||
@ -79,7 +81,7 @@ void CHC::analyze(SourceUnit const& _source)
|
|||||||
|
|
||||||
vector<string> CHC::unhandledQueries() const
|
vector<string> CHC::unhandledQueries() const
|
||||||
{
|
{
|
||||||
if (auto smtlib2 = dynamic_cast<smtutil::CHCSmtLib2Interface const*>(m_interface.get()))
|
if (auto smtlib2 = dynamic_cast<CHCSmtLib2Interface const*>(m_interface.get()))
|
||||||
return smtlib2->unhandledQueries();
|
return smtlib2->unhandledQueries();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
@ -92,13 +94,15 @@ bool CHC::visit(ContractDefinition const& _contract)
|
|||||||
initContract(_contract);
|
initContract(_contract);
|
||||||
|
|
||||||
m_stateVariables = SMTEncoder::stateVariablesIncludingInheritedAndPrivate(_contract);
|
m_stateVariables = SMTEncoder::stateVariablesIncludingInheritedAndPrivate(_contract);
|
||||||
m_stateSorts = stateSorts(_contract);
|
|
||||||
|
|
||||||
clearIndices(&_contract);
|
clearIndices(&_contract);
|
||||||
|
|
||||||
string suffix = _contract.name() + "_" + to_string(_contract.id());
|
solAssert(m_currentContract, "");
|
||||||
m_constructorSummaryPredicate = createSymbolicBlock(constructorSort(), "summary_constructor_" + suffix, &_contract);
|
m_constructorSummaryPredicate = createSymbolicBlock(
|
||||||
m_implicitConstructorPredicate = createSymbolicBlock(arity0FunctionSort(), "implicit_constructor_" + suffix, &_contract);
|
constructorSort(*m_currentContract),
|
||||||
|
"summary_constructor_" + contractSuffix(_contract),
|
||||||
|
&_contract
|
||||||
|
);
|
||||||
auto stateExprs = currentStateVariables();
|
auto stateExprs = currentStateVariables();
|
||||||
setCurrentBlock(*m_interfaces.at(m_currentContract), &stateExprs);
|
setCurrentBlock(*m_interfaces.at(m_currentContract), &stateExprs);
|
||||||
|
|
||||||
@ -108,7 +112,12 @@ bool CHC::visit(ContractDefinition const& _contract)
|
|||||||
|
|
||||||
void CHC::endVisit(ContractDefinition const& _contract)
|
void CHC::endVisit(ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
auto implicitConstructor = (*m_implicitConstructorPredicate)({});
|
auto implicitConstructorPredicate = createSymbolicBlock(
|
||||||
|
implicitConstructorSort(),
|
||||||
|
"implicit_constructor_" + contractSuffix(_contract),
|
||||||
|
&_contract
|
||||||
|
);
|
||||||
|
auto implicitConstructor = (*implicitConstructorPredicate)({});
|
||||||
addRule(implicitConstructor, implicitConstructor.name);
|
addRule(implicitConstructor, implicitConstructor.name);
|
||||||
m_currentBlock = implicitConstructor;
|
m_currentBlock = implicitConstructor;
|
||||||
m_context.addAssertion(m_error.currentValue() == 0);
|
m_context.addAssertion(m_error.currentValue() == 0);
|
||||||
@ -204,7 +213,12 @@ void CHC::endVisit(FunctionDefinition const& _function)
|
|||||||
if (_function.isConstructor())
|
if (_function.isConstructor())
|
||||||
{
|
{
|
||||||
string suffix = m_currentContract->name() + "_" + to_string(m_currentContract->id());
|
string suffix = m_currentContract->name() + "_" + to_string(m_currentContract->id());
|
||||||
auto constructorExit = createSymbolicBlock(constructorSort(), "constructor_exit_" + suffix, m_currentContract);
|
solAssert(m_currentContract, "");
|
||||||
|
auto constructorExit = createSymbolicBlock(
|
||||||
|
constructorSort(*m_currentContract),
|
||||||
|
"constructor_exit_" + suffix,
|
||||||
|
m_currentContract
|
||||||
|
);
|
||||||
connectBlocks(m_currentBlock, predicate(*constructorExit, currentFunctionVariables(*m_currentContract)));
|
connectBlocks(m_currentBlock, predicate(*constructorExit, currentFunctionVariables(*m_currentContract)));
|
||||||
|
|
||||||
clearIndices(m_currentContract, m_currentFunction);
|
clearIndices(m_currentContract, m_currentFunction);
|
||||||
@ -566,7 +580,7 @@ void CHC::makeArrayPopVerificationTarget(FunctionCall const& _arrayPop)
|
|||||||
|
|
||||||
auto memberAccess = dynamic_cast<MemberAccess const*>(&_arrayPop.expression());
|
auto memberAccess = dynamic_cast<MemberAccess const*>(&_arrayPop.expression());
|
||||||
solAssert(memberAccess, "");
|
solAssert(memberAccess, "");
|
||||||
auto symbArray = dynamic_pointer_cast<smt::SymbolicArrayVariable>(m_context.expression(memberAccess->expression()));
|
auto symbArray = dynamic_pointer_cast<SymbolicArrayVariable>(m_context.expression(memberAccess->expression()));
|
||||||
solAssert(symbArray, "");
|
solAssert(symbArray, "");
|
||||||
|
|
||||||
auto previousError = m_error.currentValue();
|
auto previousError = m_error.currentValue();
|
||||||
@ -662,15 +676,15 @@ void CHC::resetSourceAnalysis()
|
|||||||
if (usesZ3)
|
if (usesZ3)
|
||||||
{
|
{
|
||||||
/// z3::fixedpoint does not have a reset mechanism, so we need to create another.
|
/// z3::fixedpoint does not have a reset mechanism, so we need to create another.
|
||||||
m_interface.reset(new smtutil::Z3CHCInterface());
|
m_interface.reset(new Z3CHCInterface());
|
||||||
auto z3Interface = dynamic_cast<smtutil::Z3CHCInterface const*>(m_interface.get());
|
auto z3Interface = dynamic_cast<Z3CHCInterface const*>(m_interface.get());
|
||||||
solAssert(z3Interface, "");
|
solAssert(z3Interface, "");
|
||||||
m_context.setSolver(z3Interface->z3Interface());
|
m_context.setSolver(z3Interface->z3Interface());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!usesZ3)
|
if (!usesZ3)
|
||||||
{
|
{
|
||||||
auto smtlib2Interface = dynamic_cast<smtutil::CHCSmtLib2Interface*>(m_interface.get());
|
auto smtlib2Interface = dynamic_cast<CHCSmtLib2Interface*>(m_interface.get());
|
||||||
smtlib2Interface->reset();
|
smtlib2Interface->reset();
|
||||||
solAssert(smtlib2Interface, "");
|
solAssert(smtlib2Interface, "");
|
||||||
m_context.setSolver(smtlib2Interface->smtlib2Interface());
|
m_context.setSolver(smtlib2Interface->smtlib2Interface());
|
||||||
@ -682,7 +696,6 @@ void CHC::resetSourceAnalysis()
|
|||||||
|
|
||||||
void CHC::resetContractAnalysis()
|
void CHC::resetContractAnalysis()
|
||||||
{
|
{
|
||||||
m_stateSorts.clear();
|
|
||||||
m_stateVariables.clear();
|
m_stateVariables.clear();
|
||||||
m_unknownFunctionCallSeen = false;
|
m_unknownFunctionCallSeen = false;
|
||||||
m_breakDest = nullptr;
|
m_breakDest = nullptr;
|
||||||
@ -739,117 +752,18 @@ set<frontend::Expression const*, CHC::IdCompare> CHC::transactionAssertions(ASTN
|
|||||||
return assertions;
|
return assertions;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<smtutil::SortPointer> CHC::stateSorts(ContractDefinition const& _contract)
|
SortPointer CHC::sort(FunctionDefinition const& _function)
|
||||||
{
|
{
|
||||||
return applyMap(
|
return functionSort(_function, m_currentContract);
|
||||||
SMTEncoder::stateVariablesIncludingInheritedAndPrivate(_contract),
|
|
||||||
[](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
smtutil::SortPointer CHC::constructorSort()
|
SortPointer CHC::sort(ASTNode const* _node)
|
||||||
{
|
|
||||||
solAssert(m_currentContract, "");
|
|
||||||
if (auto const* constructor = m_currentContract->constructor())
|
|
||||||
return sort(*constructor);
|
|
||||||
|
|
||||||
return make_shared<smtutil::FunctionSort>(
|
|
||||||
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + m_stateSorts,
|
|
||||||
smtutil::SortProvider::boolSort
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
smtutil::SortPointer CHC::interfaceSort()
|
|
||||||
{
|
|
||||||
solAssert(m_currentContract, "");
|
|
||||||
return interfaceSort(*m_currentContract);
|
|
||||||
}
|
|
||||||
|
|
||||||
smtutil::SortPointer CHC::nondetInterfaceSort()
|
|
||||||
{
|
|
||||||
solAssert(m_currentContract, "");
|
|
||||||
return nondetInterfaceSort(*m_currentContract);
|
|
||||||
}
|
|
||||||
|
|
||||||
smtutil::SortPointer CHC::interfaceSort(ContractDefinition const& _contract)
|
|
||||||
{
|
|
||||||
return make_shared<smtutil::FunctionSort>(
|
|
||||||
stateSorts(_contract),
|
|
||||||
smtutil::SortProvider::boolSort
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
smtutil::SortPointer CHC::nondetInterfaceSort(ContractDefinition const& _contract)
|
|
||||||
{
|
|
||||||
auto sorts = stateSorts(_contract);
|
|
||||||
return make_shared<smtutil::FunctionSort>(
|
|
||||||
sorts + sorts,
|
|
||||||
smtutil::SortProvider::boolSort
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
smtutil::SortPointer CHC::arity0FunctionSort() const
|
|
||||||
{
|
|
||||||
return make_shared<smtutil::FunctionSort>(
|
|
||||||
vector<smtutil::SortPointer>(),
|
|
||||||
smtutil::SortProvider::boolSort
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A function in the symbolic CFG requires:
|
|
||||||
/// - Index of failed assertion. 0 means no assertion failed.
|
|
||||||
/// - 2 sets of state variables:
|
|
||||||
/// - State variables at the beginning of the current function, immutable
|
|
||||||
/// - Current state variables
|
|
||||||
/// At the beginning of the function these must equal set 1
|
|
||||||
/// - 2 sets of input variables:
|
|
||||||
/// - Input variables at the beginning of the current function, immutable
|
|
||||||
/// - Current input variables
|
|
||||||
/// At the beginning of the function these must equal set 1
|
|
||||||
/// - 1 set of output variables
|
|
||||||
smtutil::SortPointer CHC::sort(FunctionDefinition const& _function)
|
|
||||||
{
|
|
||||||
auto smtSort = [](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); };
|
|
||||||
auto inputSorts = applyMap(_function.parameters(), smtSort);
|
|
||||||
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
|
|
||||||
return make_shared<smtutil::FunctionSort>(
|
|
||||||
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} + m_stateSorts + inputSorts + m_stateSorts + inputSorts + outputSorts,
|
|
||||||
smtutil::SortProvider::boolSort
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
smtutil::SortPointer CHC::sort(ASTNode const* _node)
|
|
||||||
{
|
{
|
||||||
if (auto funDef = dynamic_cast<FunctionDefinition const*>(_node))
|
if (auto funDef = dynamic_cast<FunctionDefinition const*>(_node))
|
||||||
return sort(*funDef);
|
return sort(*funDef);
|
||||||
|
|
||||||
auto fSort = dynamic_pointer_cast<smtutil::FunctionSort>(sort(*m_currentFunction));
|
solAssert(m_currentFunction, "");
|
||||||
solAssert(fSort, "");
|
return functionBodySort(*m_currentFunction, m_currentContract);
|
||||||
|
|
||||||
auto smtSort = [](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); };
|
|
||||||
return make_shared<smtutil::FunctionSort>(
|
|
||||||
fSort->domain + applyMap(m_currentFunction->localVariables(), smtSort),
|
|
||||||
smtutil::SortProvider::boolSort
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
smtutil::SortPointer CHC::summarySort(FunctionDefinition const& _function, ContractDefinition const& _contract)
|
|
||||||
{
|
|
||||||
auto stateVariables = SMTEncoder::stateVariablesIncludingInheritedAndPrivate(_contract);
|
|
||||||
auto sorts = stateSorts(_contract);
|
|
||||||
|
|
||||||
auto smtSort = [](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); };
|
|
||||||
auto inputSorts = applyMap(_function.parameters(), smtSort);
|
|
||||||
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
|
|
||||||
return make_shared<smtutil::FunctionSort>(
|
|
||||||
vector<smtutil::SortPointer>{smtutil::SortProvider::uintSort} +
|
|
||||||
sorts +
|
|
||||||
inputSorts +
|
|
||||||
sorts +
|
|
||||||
inputSorts +
|
|
||||||
outputSorts,
|
|
||||||
smtutil::SortProvider::boolSort
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Predicate const* CHC::createSymbolicBlock(SortPointer _sort, string const& _name, ASTNode const* _node)
|
Predicate const* CHC::createSymbolicBlock(SortPointer _sort, string const& _name, ASTNode const* _node)
|
||||||
@ -987,7 +901,7 @@ Predicate const* CHC::createBlock(ASTNode const* _node, string const& _prefix)
|
|||||||
Predicate const* CHC::createSummaryBlock(FunctionDefinition const& _function, ContractDefinition const& _contract)
|
Predicate const* CHC::createSummaryBlock(FunctionDefinition const& _function, ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
auto block = createSymbolicBlock(
|
auto block = createSymbolicBlock(
|
||||||
summarySort(_function, _contract),
|
functionSort(_function, &_contract),
|
||||||
"summary_" + uniquePrefix() + "_" + predicateName(&_function, &_contract),
|
"summary_" + uniquePrefix() + "_" + predicateName(&_function, &_contract),
|
||||||
&_function
|
&_function
|
||||||
);
|
);
|
||||||
@ -1157,14 +1071,14 @@ void CHC::addRule(smtutil::Expression const& _rule, string const& _ruleName)
|
|||||||
m_interface->addRule(_rule, _ruleName);
|
m_interface->addRule(_rule, _ruleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
pair<smtutil::CheckResult, CHCSolverInterface::CexGraph> CHC::query(smtutil::Expression const& _query, langutil::SourceLocation const& _location)
|
pair<CheckResult, CHCSolverInterface::CexGraph> CHC::query(smtutil::Expression const& _query, langutil::SourceLocation const& _location)
|
||||||
{
|
{
|
||||||
smtutil::CheckResult result;
|
CheckResult result;
|
||||||
CHCSolverInterface::CexGraph cex;
|
CHCSolverInterface::CexGraph cex;
|
||||||
tie(result, cex) = m_interface->query(_query);
|
tie(result, cex) = m_interface->query(_query);
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case smtutil::CheckResult::SATISFIABLE:
|
case CheckResult::SATISFIABLE:
|
||||||
{
|
{
|
||||||
#ifdef HAVE_Z3
|
#ifdef HAVE_Z3
|
||||||
// Even though the problem is SAT, Spacer's pre processing makes counterexamples incomplete.
|
// Even though the problem is SAT, Spacer's pre processing makes counterexamples incomplete.
|
||||||
@ -1173,25 +1087,25 @@ pair<smtutil::CheckResult, CHCSolverInterface::CexGraph> CHC::query(smtutil::Exp
|
|||||||
solAssert(spacer, "");
|
solAssert(spacer, "");
|
||||||
spacer->setSpacerOptions(false);
|
spacer->setSpacerOptions(false);
|
||||||
|
|
||||||
smtutil::CheckResult resultNoOpt;
|
CheckResult resultNoOpt;
|
||||||
CHCSolverInterface::CexGraph cexNoOpt;
|
CHCSolverInterface::CexGraph cexNoOpt;
|
||||||
tie(resultNoOpt, cexNoOpt) = m_interface->query(_query);
|
tie(resultNoOpt, cexNoOpt) = m_interface->query(_query);
|
||||||
|
|
||||||
if (resultNoOpt == smtutil::CheckResult::SATISFIABLE)
|
if (resultNoOpt == CheckResult::SATISFIABLE)
|
||||||
cex = move(cexNoOpt);
|
cex = move(cexNoOpt);
|
||||||
|
|
||||||
spacer->setSpacerOptions(true);
|
spacer->setSpacerOptions(true);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case smtutil::CheckResult::UNSATISFIABLE:
|
case CheckResult::UNSATISFIABLE:
|
||||||
break;
|
break;
|
||||||
case smtutil::CheckResult::UNKNOWN:
|
case CheckResult::UNKNOWN:
|
||||||
break;
|
break;
|
||||||
case smtutil::CheckResult::CONFLICTING:
|
case CheckResult::CONFLICTING:
|
||||||
m_outerErrorReporter.warning(1988_error, _location, "At least two SMT solvers provided conflicting answers. Results might not be sound.");
|
m_outerErrorReporter.warning(1988_error, _location, "At least two SMT solvers provided conflicting answers. Results might not be sound.");
|
||||||
break;
|
break;
|
||||||
case smtutil::CheckResult::ERROR:
|
case CheckResult::ERROR:
|
||||||
m_outerErrorReporter.warning(1218_error, _location, "Error trying to invoke SMT solver.");
|
m_outerErrorReporter.warning(1218_error, _location, "Error trying to invoke SMT solver.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1339,9 +1253,9 @@ void CHC::checkAndReportTarget(
|
|||||||
createErrorBlock();
|
createErrorBlock();
|
||||||
connectBlocks(_target.value, error(), _target.constraints && (_target.errorId == _errorId));
|
connectBlocks(_target.value, error(), _target.constraints && (_target.errorId == _errorId));
|
||||||
auto const& [result, model] = query(error(), _scope->location());
|
auto const& [result, model] = query(error(), _scope->location());
|
||||||
if (result == smtutil::CheckResult::UNSATISFIABLE)
|
if (result == CheckResult::UNSATISFIABLE)
|
||||||
m_safeTargets[_scope].insert(_target.type);
|
m_safeTargets[_scope].insert(_target.type);
|
||||||
else if (result == smtutil::CheckResult::SATISFIABLE)
|
else if (result == CheckResult::SATISFIABLE)
|
||||||
{
|
{
|
||||||
solAssert(!_satMsg.empty(), "");
|
solAssert(!_satMsg.empty(), "");
|
||||||
m_unsafeTargets[_scope].insert(_target.type);
|
m_unsafeTargets[_scope].insert(_target.type);
|
||||||
@ -1477,7 +1391,7 @@ optional<string> CHC::generateCounterexample(CHCSolverInterface::CexGraph const&
|
|||||||
return localState + "\nTransaction trace:\n" + boost::algorithm::join(boost::adaptors::reverse(path), "\n");
|
return localState + "\nTransaction trace:\n" + boost::algorithm::join(boost::adaptors::reverse(path), "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
string CHC::cex2dot(smtutil::CHCSolverInterface::CexGraph const& _cex)
|
string CHC::cex2dot(CHCSolverInterface::CexGraph const& _cex)
|
||||||
{
|
{
|
||||||
string dot = "digraph {\n";
|
string dot = "digraph {\n";
|
||||||
|
|
||||||
@ -1498,6 +1412,11 @@ string CHC::uniquePrefix()
|
|||||||
return to_string(m_blockCounter++);
|
return to_string(m_blockCounter++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string CHC::contractSuffix(ContractDefinition const& _contract)
|
||||||
|
{
|
||||||
|
return _contract.name() + "_" + to_string(_contract.id());
|
||||||
|
}
|
||||||
|
|
||||||
unsigned CHC::newErrorId(frontend::Expression const& _expr)
|
unsigned CHC::newErrorId(frontend::Expression const& _expr)
|
||||||
{
|
{
|
||||||
unsigned errorId = m_context.newUniqueId();
|
unsigned errorId = m_context.newUniqueId();
|
||||||
|
@ -117,19 +117,8 @@ private:
|
|||||||
|
|
||||||
/// Sort helpers.
|
/// Sort helpers.
|
||||||
//@{
|
//@{
|
||||||
static std::vector<smtutil::SortPointer> stateSorts(ContractDefinition const& _contract);
|
|
||||||
smtutil::SortPointer constructorSort();
|
|
||||||
smtutil::SortPointer interfaceSort();
|
|
||||||
smtutil::SortPointer nondetInterfaceSort();
|
|
||||||
static smtutil::SortPointer interfaceSort(ContractDefinition const& _const);
|
|
||||||
static smtutil::SortPointer nondetInterfaceSort(ContractDefinition const& _const);
|
|
||||||
smtutil::SortPointer arity0FunctionSort() const;
|
|
||||||
smtutil::SortPointer sort(FunctionDefinition const& _function);
|
smtutil::SortPointer sort(FunctionDefinition const& _function);
|
||||||
smtutil::SortPointer sort(ASTNode const* _block);
|
smtutil::SortPointer sort(ASTNode const* _block);
|
||||||
/// @returns the sort of a predicate that represents the summary of _function in the scope of _contract.
|
|
||||||
/// The _contract is also needed because the same function might be in many contracts due to inheritance,
|
|
||||||
/// where the sort changes because the set of state variables might change.
|
|
||||||
static smtutil::SortPointer summarySort(FunctionDefinition const& _function, ContractDefinition const& _contract);
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/// Predicate helpers.
|
/// Predicate helpers.
|
||||||
@ -246,10 +235,13 @@ private:
|
|||||||
|
|
||||||
/// Misc.
|
/// Misc.
|
||||||
//@{
|
//@{
|
||||||
/// Returns a prefix to be used in a new unique block name
|
/// @returns a prefix to be used in a new unique block name
|
||||||
/// and increases the block counter.
|
/// and increases the block counter.
|
||||||
std::string uniquePrefix();
|
std::string uniquePrefix();
|
||||||
|
|
||||||
|
/// @returns a suffix to be used by contract related predicates.
|
||||||
|
std::string contractSuffix(ContractDefinition const& _contract);
|
||||||
|
|
||||||
/// @returns a new unique error id associated with _expr and stores
|
/// @returns a new unique error id associated with _expr and stores
|
||||||
/// it into m_errorIds.
|
/// it into m_errorIds.
|
||||||
unsigned newErrorId(Expression const& _expr);
|
unsigned newErrorId(Expression const& _expr);
|
||||||
@ -257,10 +249,6 @@ private:
|
|||||||
|
|
||||||
/// Predicates.
|
/// Predicates.
|
||||||
//@{
|
//@{
|
||||||
/// Implicit constructor predicate.
|
|
||||||
/// Explicit constructors are handled as functions.
|
|
||||||
Predicate const* m_implicitConstructorPredicate = nullptr;
|
|
||||||
|
|
||||||
/// Constructor summary predicate, exists after the constructor
|
/// Constructor summary predicate, exists after the constructor
|
||||||
/// (implicit or explicit) and before the interface.
|
/// (implicit or explicit) and before the interface.
|
||||||
Predicate const* m_constructorSummaryPredicate = nullptr;
|
Predicate const* m_constructorSummaryPredicate = nullptr;
|
||||||
@ -292,9 +280,6 @@ private:
|
|||||||
|
|
||||||
/// Variables.
|
/// Variables.
|
||||||
//@{
|
//@{
|
||||||
/// State variables sorts.
|
|
||||||
/// Used by all predicates.
|
|
||||||
std::vector<smtutil::SortPointer> m_stateSorts;
|
|
||||||
/// State variables.
|
/// State variables.
|
||||||
/// Used to create all predicates.
|
/// Used to create all predicates.
|
||||||
std::vector<VariableDeclaration const*> m_stateVariables;
|
std::vector<VariableDeclaration const*> m_stateVariables;
|
||||||
|
111
libsolidity/formal/PredicateSort.cpp
Normal file
111
libsolidity/formal/PredicateSort.cpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
|
#include <libsolidity/formal/PredicateSort.h>
|
||||||
|
|
||||||
|
#include <libsolidity/formal/SMTEncoder.h>
|
||||||
|
#include <libsolidity/formal/SymbolicTypes.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace solidity::util;
|
||||||
|
using namespace solidity::smtutil;
|
||||||
|
|
||||||
|
namespace solidity::frontend::smt
|
||||||
|
{
|
||||||
|
|
||||||
|
SortPointer interfaceSort(ContractDefinition const& _contract)
|
||||||
|
{
|
||||||
|
return make_shared<FunctionSort>(
|
||||||
|
stateSorts(_contract),
|
||||||
|
SortProvider::boolSort
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SortPointer nondetInterfaceSort(ContractDefinition const& _contract)
|
||||||
|
{
|
||||||
|
auto varSorts = stateSorts(_contract);
|
||||||
|
return make_shared<FunctionSort>(
|
||||||
|
varSorts + varSorts,
|
||||||
|
SortProvider::boolSort
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SortPointer implicitConstructorSort()
|
||||||
|
{
|
||||||
|
return arity0FunctionSort();
|
||||||
|
}
|
||||||
|
|
||||||
|
SortPointer constructorSort(ContractDefinition const& _contract)
|
||||||
|
{
|
||||||
|
if (auto const* constructor = _contract.constructor())
|
||||||
|
return functionSort(*constructor, &_contract);
|
||||||
|
|
||||||
|
return make_shared<FunctionSort>(
|
||||||
|
vector<SortPointer>{SortProvider::uintSort} + stateSorts(_contract),
|
||||||
|
SortProvider::boolSort
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SortPointer functionSort(FunctionDefinition const& _function, ContractDefinition const* _contract)
|
||||||
|
{
|
||||||
|
auto smtSort = [](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); };
|
||||||
|
auto varSorts = _contract ? stateSorts(*_contract) : vector<SortPointer>{};
|
||||||
|
auto inputSorts = applyMap(_function.parameters(), smtSort);
|
||||||
|
auto outputSorts = applyMap(_function.returnParameters(), smtSort);
|
||||||
|
return make_shared<FunctionSort>(
|
||||||
|
vector<SortPointer>{SortProvider::uintSort} +
|
||||||
|
varSorts +
|
||||||
|
inputSorts +
|
||||||
|
varSorts +
|
||||||
|
inputSorts +
|
||||||
|
outputSorts,
|
||||||
|
SortProvider::boolSort
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SortPointer functionBodySort(FunctionDefinition const& _function, ContractDefinition const* _contract)
|
||||||
|
{
|
||||||
|
auto fSort = dynamic_pointer_cast<FunctionSort>(functionSort(_function, _contract));
|
||||||
|
solAssert(fSort, "");
|
||||||
|
|
||||||
|
auto smtSort = [](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); };
|
||||||
|
return make_shared<FunctionSort>(
|
||||||
|
fSort->domain + applyMap(_function.localVariables(), smtSort),
|
||||||
|
SortProvider::boolSort
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SortPointer arity0FunctionSort()
|
||||||
|
{
|
||||||
|
return make_shared<FunctionSort>(
|
||||||
|
vector<SortPointer>(),
|
||||||
|
SortProvider::boolSort
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helpers
|
||||||
|
|
||||||
|
vector<SortPointer> stateSorts(ContractDefinition const& _contract)
|
||||||
|
{
|
||||||
|
return applyMap(
|
||||||
|
SMTEncoder::stateVariablesIncludingInheritedAndPrivate(_contract),
|
||||||
|
[](auto _var) { return smt::smtSortAbstractFunction(*_var->type()); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
82
libsolidity/formal/PredicateSort.h
Normal file
82
libsolidity/formal/PredicateSort.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
solidity is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
solidity is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libsolidity/formal/Predicate.h>
|
||||||
|
|
||||||
|
#include <libsmtutil/Sorts.h>
|
||||||
|
|
||||||
|
namespace solidity::frontend::smt
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file represents the specification for CHC predicate sorts.
|
||||||
|
* Types of predicates:
|
||||||
|
*
|
||||||
|
* 1. Interface
|
||||||
|
* The idle state of a contract. Signature:
|
||||||
|
* interface(stateVariables).
|
||||||
|
*
|
||||||
|
* 2. Nondet interface
|
||||||
|
* The nondeterminism behavior of a contract. Signature:
|
||||||
|
* nondet_interface(stateVariables, stateVariables').
|
||||||
|
*
|
||||||
|
* 3. Implicit constructor
|
||||||
|
* The implicit constructor of a contract, that is, without input parameters. Signature:
|
||||||
|
* implicit_constructor().
|
||||||
|
*
|
||||||
|
* 4. Constructor entry/summary
|
||||||
|
* The summary of an implicit constructor. Signature:
|
||||||
|
* constructor_summary(error, stateVariables').
|
||||||
|
*
|
||||||
|
* 5. Function entry/summary
|
||||||
|
* The entry point of a function definition. Signature:
|
||||||
|
* function_entry(error, stateVariables, inputVariables, stateVariables', inputVariables', outputVariables').
|
||||||
|
*
|
||||||
|
* 6. Function body
|
||||||
|
* Use for any predicate within a function. Signature:
|
||||||
|
* function_body(error, stateVariables, inputVariables, stateVariables', inputVariables', outputVariables', localVariables).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// @returns the interface predicate sort for _contract.
|
||||||
|
smtutil::SortPointer interfaceSort(ContractDefinition const& _contract);
|
||||||
|
|
||||||
|
/// @returns the nondeterminisc interface predicate sort for _contract.
|
||||||
|
smtutil::SortPointer nondetInterfaceSort(ContractDefinition const& _contract);
|
||||||
|
|
||||||
|
/// @returns the implicit constructor predicate sort.
|
||||||
|
smtutil::SortPointer implicitConstructorSort();
|
||||||
|
|
||||||
|
/// @returns the constructor entry/summary predicate sort for _contract.
|
||||||
|
smtutil::SortPointer constructorSort(ContractDefinition const& _contract);
|
||||||
|
|
||||||
|
/// @returns the function entry/summary predicate sort for _function contained in _contract.
|
||||||
|
smtutil::SortPointer functionSort(FunctionDefinition const& _function, ContractDefinition const* _contract);
|
||||||
|
|
||||||
|
/// @returns the function body predicate sort for _function contained in _contract.
|
||||||
|
smtutil::SortPointer functionBodySort(FunctionDefinition const& _function, ContractDefinition const* _contract);
|
||||||
|
|
||||||
|
/// @returns the sort of a predicate without parameters.
|
||||||
|
smtutil::SortPointer arity0FunctionSort();
|
||||||
|
|
||||||
|
/// Helpers
|
||||||
|
|
||||||
|
std::vector<smtutil::SortPointer> stateSorts(ContractDefinition const& _contract) ;
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user