mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add expression substitution to Predicate
This commit is contained in:
parent
ce72d7cd26
commit
9bcd2c18e4
@ -26,10 +26,13 @@
|
|||||||
#include <libsolidity/ast/TypeProvider.h>
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/join.hpp>
|
#include <boost/algorithm/string/join.hpp>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
#include <range/v3/view.hpp>
|
#include <range/v3/view.hpp>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
using boost::algorithm::starts_with;
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::smtutil;
|
using namespace solidity::smtutil;
|
||||||
using namespace solidity::frontend;
|
using namespace solidity::frontend;
|
||||||
@ -198,6 +201,11 @@ bool Predicate::isInterface() const
|
|||||||
return m_type == PredicateType::Interface;
|
return m_type == PredicateType::Interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Predicate::isNondetInterface() const
|
||||||
|
{
|
||||||
|
return m_type == PredicateType::NondetInterface;
|
||||||
|
}
|
||||||
|
|
||||||
string Predicate::formatSummaryCall(
|
string Predicate::formatSummaryCall(
|
||||||
vector<smtutil::Expression> const& _args,
|
vector<smtutil::Expression> const& _args,
|
||||||
langutil::CharStreamProvider const& _charStreamProvider,
|
langutil::CharStreamProvider const& _charStreamProvider,
|
||||||
@ -418,6 +426,50 @@ pair<vector<optional<string>>, vector<VariableDeclaration const*>> Predicate::lo
|
|||||||
return {formatExpressions(outValuesInScope, outTypes), localVarsInScope};
|
return {formatExpressions(outValuesInScope, outTypes), localVarsInScope};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map<string, string> Predicate::expressionSubstitution(smtutil::Expression const& _predExpr) const
|
||||||
|
{
|
||||||
|
map<string, string> subst;
|
||||||
|
string predName = functor().name;
|
||||||
|
|
||||||
|
solAssert(contextContract(), "");
|
||||||
|
auto const& stateVars = SMTEncoder::stateVariablesIncludingInheritedAndPrivate(*contextContract());
|
||||||
|
|
||||||
|
auto nArgs = _predExpr.arguments.size();
|
||||||
|
|
||||||
|
// The signature of an interface predicate is
|
||||||
|
// interface(this, abiFunctions, cryptoFunctions, blockchainState, stateVariables).
|
||||||
|
// An invariant for an interface predicate is a contract
|
||||||
|
// invariant over its state, for example `x <= 0`.
|
||||||
|
if (isInterface())
|
||||||
|
{
|
||||||
|
solAssert(starts_with(predName, "interface"), "");
|
||||||
|
subst[_predExpr.arguments.at(0).name] = "address(this)";
|
||||||
|
solAssert(nArgs == stateVars.size() + 4, "");
|
||||||
|
for (size_t i = nArgs - stateVars.size(); i < nArgs; ++i)
|
||||||
|
subst[_predExpr.arguments.at(i).name] = stateVars.at(i - 4)->name();
|
||||||
|
}
|
||||||
|
// The signature of a nondet interface predicate is
|
||||||
|
// nondet_interface(error, this, abiFunctions, cryptoFunctions, blockchainState, stateVariables, blockchainState', stateVariables').
|
||||||
|
// An invariant for a nondet interface predicate is a reentrancy property
|
||||||
|
// over the pre and post state variables of a contract, where pre state vars
|
||||||
|
// are represented by the variable's name and post state vars are represented
|
||||||
|
// by the primed variable's name, for example
|
||||||
|
// `(x <= 0) => (x' <= 100)`.
|
||||||
|
else if (isNondetInterface())
|
||||||
|
{
|
||||||
|
solAssert(starts_with(predName, "nondet_interface"), "");
|
||||||
|
subst[_predExpr.arguments.at(0).name] = "<errorCode>";
|
||||||
|
subst[_predExpr.arguments.at(1).name] = "address(this)";
|
||||||
|
solAssert(nArgs == stateVars.size() * 2 + 6, "");
|
||||||
|
for (size_t i = nArgs - stateVars.size(), s = 0; i < nArgs; ++i, ++s)
|
||||||
|
subst[_predExpr.arguments.at(i).name] = stateVars.at(s)->name() + "'";
|
||||||
|
for (size_t i = nArgs - (stateVars.size() * 2 + 1), s = 0; i < nArgs - (stateVars.size() + 1); ++i, ++s)
|
||||||
|
subst[_predExpr.arguments.at(i).name] = stateVars.at(s)->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
return subst;
|
||||||
|
}
|
||||||
|
|
||||||
vector<optional<string>> Predicate::formatExpressions(vector<smtutil::Expression> const& _exprs, vector<Type const*> const& _types) const
|
vector<optional<string>> Predicate::formatExpressions(vector<smtutil::Expression> const& _exprs, vector<Type const*> const& _types) const
|
||||||
{
|
{
|
||||||
solAssert(_exprs.size() == _types.size(), "");
|
solAssert(_exprs.size() == _types.size(), "");
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include <libsolidity/formal/SymbolicVariables.h>
|
#include <libsolidity/formal/SymbolicVariables.h>
|
||||||
#include <libsolidity/formal/SymbolicVariables.h>
|
#include <libsolidity/formal/SymbolicVariables.h>
|
||||||
|
|
||||||
|
#include <libsolidity/ast/AST.h>
|
||||||
|
|
||||||
#include <libsmtutil/Sorts.h>
|
#include <libsmtutil/Sorts.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -143,6 +145,9 @@ public:
|
|||||||
/// @returns true if this predicate represents an interface.
|
/// @returns true if this predicate represents an interface.
|
||||||
bool isInterface() const;
|
bool isInterface() const;
|
||||||
|
|
||||||
|
/// @returns true if this predicate represents a nondeterministic interface.
|
||||||
|
bool isNondetInterface() const;
|
||||||
|
|
||||||
PredicateType type() const { return m_type; }
|
PredicateType type() const { return m_type; }
|
||||||
|
|
||||||
/// @returns a formatted string representing a call to this predicate
|
/// @returns a formatted string representing a call to this predicate
|
||||||
@ -168,6 +173,10 @@ public:
|
|||||||
/// @returns the values of the local variables used by this predicate.
|
/// @returns the values of the local variables used by this predicate.
|
||||||
std::pair<std::vector<std::optional<std::string>>, std::vector<VariableDeclaration const*>> localVariableValues(std::vector<smtutil::Expression> const& _args) const;
|
std::pair<std::vector<std::optional<std::string>>, std::vector<VariableDeclaration const*>> localVariableValues(std::vector<smtutil::Expression> const& _args) const;
|
||||||
|
|
||||||
|
/// @returns a substitution map from the arguments of _predExpr
|
||||||
|
/// to a Solidity-like expression.
|
||||||
|
std::map<std::string, std::string> expressionSubstitution(smtutil::Expression const& _predExpr) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// @returns the formatted version of the given SMT expressions. Those expressions must be SMT constants.
|
/// @returns the formatted version of the given SMT expressions. Those expressions must be SMT constants.
|
||||||
std::vector<std::optional<std::string>> formatExpressions(std::vector<smtutil::Expression> const& _exprs, std::vector<Type const*> const& _types) const;
|
std::vector<std::optional<std::string>> formatExpressions(std::vector<smtutil::Expression> const& _exprs, std::vector<Type const*> const& _types) const;
|
||||||
@ -208,4 +217,16 @@ private:
|
|||||||
std::vector<ScopeOpener const*> const m_scopeStack;
|
std::vector<ScopeOpener const*> const m_scopeStack;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PredicateCompare
|
||||||
|
{
|
||||||
|
bool operator()(Predicate const* lhs, Predicate const* rhs) const
|
||||||
|
{
|
||||||
|
// We cannot use m_node->id() because different predicates may
|
||||||
|
// represent the same program node.
|
||||||
|
// We use the symbolic name since it is unique per predicate and
|
||||||
|
// the order does not really matter.
|
||||||
|
return lhs->functor().name < rhs->functor().name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user