2020-08-13 12:00:33 +00:00
|
|
|
/*
|
|
|
|
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/SymbolicVariables.h>
|
|
|
|
#include <libsolidity/formal/SymbolicVariables.h>
|
|
|
|
|
2021-10-06 09:48:15 +00:00
|
|
|
#include <libsolidity/ast/AST.h>
|
|
|
|
|
2020-08-13 12:00:33 +00:00
|
|
|
#include <libsmtutil/Sorts.h>
|
|
|
|
|
|
|
|
#include <map>
|
2020-08-19 11:53:16 +00:00
|
|
|
#include <optional>
|
2020-08-13 12:00:33 +00:00
|
|
|
#include <vector>
|
|
|
|
|
2021-07-01 15:28:06 +00:00
|
|
|
namespace solidity::langutil
|
|
|
|
{
|
|
|
|
class CharStreamProvider;
|
|
|
|
}
|
|
|
|
|
2020-08-13 12:00:33 +00:00
|
|
|
namespace solidity::frontend
|
|
|
|
{
|
|
|
|
|
2020-09-16 09:47:54 +00:00
|
|
|
enum class PredicateType
|
|
|
|
{
|
|
|
|
Interface,
|
|
|
|
NondetInterface,
|
|
|
|
ConstructorSummary,
|
|
|
|
FunctionSummary,
|
|
|
|
FunctionBlock,
|
2021-01-21 18:04:34 +00:00
|
|
|
FunctionErrorBlock,
|
2021-01-06 15:34:16 +00:00
|
|
|
InternalCall,
|
2021-01-11 21:17:32 +00:00
|
|
|
ExternalCallTrusted,
|
|
|
|
ExternalCallUntrusted,
|
2020-09-24 17:24:33 +00:00
|
|
|
Error,
|
|
|
|
Custom
|
2020-09-16 09:47:54 +00:00
|
|
|
};
|
|
|
|
|
2020-08-13 12:00:33 +00:00
|
|
|
/**
|
|
|
|
* Represents a predicate used by the CHC engine.
|
|
|
|
*/
|
|
|
|
class Predicate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static Predicate const* create(
|
|
|
|
smtutil::SortPointer _sort,
|
|
|
|
std::string _name,
|
2020-09-16 09:47:54 +00:00
|
|
|
PredicateType _type,
|
2020-08-13 12:00:33 +00:00
|
|
|
smt::EncodingContext& _context,
|
2021-01-22 10:42:40 +00:00
|
|
|
ASTNode const* _node = nullptr,
|
2021-01-21 18:04:34 +00:00
|
|
|
ContractDefinition const* _contractContext = nullptr,
|
|
|
|
std::vector<ScopeOpener const*> _scopeStack = {}
|
2020-08-13 12:00:33 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
Predicate(
|
|
|
|
smt::SymbolicFunctionVariable&& _predicate,
|
2020-09-16 09:47:54 +00:00
|
|
|
PredicateType _type,
|
2021-01-22 10:42:40 +00:00
|
|
|
ASTNode const* _node = nullptr,
|
2021-01-21 18:04:34 +00:00
|
|
|
ContractDefinition const* _contractContext = nullptr,
|
|
|
|
std::vector<ScopeOpener const*> _scopeStack = {}
|
2020-08-13 12:00:33 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
/// Predicate should not be copiable.
|
|
|
|
Predicate(Predicate const&) = delete;
|
|
|
|
Predicate& operator=(Predicate const&) = delete;
|
|
|
|
|
|
|
|
/// @returns the Predicate associated with _name.
|
|
|
|
static Predicate const* predicate(std::string const& _name);
|
|
|
|
|
|
|
|
/// Resets all the allocated predicates.
|
|
|
|
static void reset();
|
|
|
|
|
|
|
|
/// @returns a function application of the predicate over _args.
|
|
|
|
smtutil::Expression operator()(std::vector<smtutil::Expression> const& _args) const;
|
|
|
|
|
|
|
|
/// @returns the function declaration of the predicate.
|
|
|
|
smtutil::Expression functor() const;
|
|
|
|
/// @returns the function declaration of the predicate with index _idx.
|
|
|
|
smtutil::Expression functor(unsigned _idx) const;
|
|
|
|
/// Increases the index of the function declaration of the predicate.
|
|
|
|
void newFunctor();
|
|
|
|
|
|
|
|
/// @returns the program node this predicate represents.
|
|
|
|
ASTNode const* programNode() const;
|
|
|
|
|
2021-01-21 18:04:34 +00:00
|
|
|
/// @returns the ContractDefinition of the most derived contract
|
|
|
|
/// being analyzed.
|
|
|
|
ContractDefinition const* contextContract() const;
|
|
|
|
|
2020-08-19 11:53:16 +00:00
|
|
|
/// @returns the ContractDefinition that this predicate represents
|
|
|
|
/// or nullptr otherwise.
|
|
|
|
ContractDefinition const* programContract() const;
|
|
|
|
|
|
|
|
/// @returns the FunctionDefinition that this predicate represents
|
|
|
|
/// or nullptr otherwise.
|
|
|
|
FunctionDefinition const* programFunction() const;
|
|
|
|
|
2021-01-11 21:17:32 +00:00
|
|
|
/// @returns the FunctionCall that this predicate represents
|
|
|
|
/// or nullptr otherwise.
|
|
|
|
FunctionCall const* programFunctionCall() const;
|
|
|
|
|
2021-10-12 09:12:18 +00:00
|
|
|
/// @returns the VariableDeclaration that this predicate represents
|
|
|
|
/// or nullptr otherwise.
|
|
|
|
VariableDeclaration const* programVariable() const;
|
|
|
|
|
2020-08-19 11:53:16 +00:00
|
|
|
/// @returns the program state variables in the scope of this predicate.
|
|
|
|
std::optional<std::vector<VariableDeclaration const*>> stateVariables() const;
|
|
|
|
|
|
|
|
/// @returns true if this predicate represents a summary.
|
|
|
|
bool isSummary() const;
|
|
|
|
|
2021-01-06 15:34:16 +00:00
|
|
|
/// @returns true if this predicate represents a function summary.
|
|
|
|
bool isFunctionSummary() const;
|
|
|
|
|
2021-01-21 18:04:34 +00:00
|
|
|
/// @returns true if this predicate represents a function block.
|
|
|
|
bool isFunctionBlock() const;
|
|
|
|
|
|
|
|
/// @returns true if this predicate represents a function error block.
|
|
|
|
bool isFunctionErrorBlock() const;
|
|
|
|
|
2021-01-06 15:34:16 +00:00
|
|
|
/// @returns true if this predicate represents an internal function call.
|
|
|
|
bool isInternalCall() const;
|
|
|
|
|
2021-01-11 21:17:32 +00:00
|
|
|
/// @returns true if this predicate represents a trusted external function call.
|
|
|
|
bool isExternalCallTrusted() const;
|
|
|
|
|
|
|
|
/// @returns true if this predicate represents an untrusted external function call.
|
|
|
|
bool isExternalCallUntrusted() const;
|
2021-01-06 15:34:16 +00:00
|
|
|
|
2021-01-06 10:55:42 +00:00
|
|
|
/// @returns true if this predicate represents a constructor summary.
|
|
|
|
bool isConstructorSummary() const;
|
|
|
|
|
2020-08-19 11:53:16 +00:00
|
|
|
/// @returns true if this predicate represents an interface.
|
|
|
|
bool isInterface() const;
|
|
|
|
|
2021-10-06 09:48:15 +00:00
|
|
|
/// @returns true if this predicate represents a nondeterministic interface.
|
|
|
|
bool isNondetInterface() const;
|
|
|
|
|
2020-09-16 09:47:54 +00:00
|
|
|
PredicateType type() const { return m_type; }
|
|
|
|
|
2020-08-19 11:53:16 +00:00
|
|
|
/// @returns a formatted string representing a call to this predicate
|
|
|
|
/// with _args.
|
2021-07-01 15:28:06 +00:00
|
|
|
std::string formatSummaryCall(
|
|
|
|
std::vector<smtutil::Expression> const& _args,
|
2021-09-16 17:18:26 +00:00
|
|
|
langutil::CharStreamProvider const& _charStreamProvider,
|
|
|
|
bool _appendTxVars = false
|
2021-07-01 15:28:06 +00:00
|
|
|
) const;
|
2020-08-19 11:53:16 +00:00
|
|
|
|
2020-08-19 16:38:56 +00:00
|
|
|
/// @returns the values of the state variables from _args at the point
|
|
|
|
/// where this summary was reached.
|
2020-10-19 11:21:05 +00:00
|
|
|
std::vector<std::optional<std::string>> summaryStateValues(std::vector<smtutil::Expression> const& _args) const;
|
2020-08-19 16:38:56 +00:00
|
|
|
|
2020-08-20 08:43:50 +00:00
|
|
|
/// @returns the values of the function input variables from _args at the point
|
|
|
|
/// where this summary was reached.
|
2020-10-19 11:21:05 +00:00
|
|
|
std::vector<std::optional<std::string>> summaryPostInputValues(std::vector<smtutil::Expression> const& _args) const;
|
2020-08-20 08:43:50 +00:00
|
|
|
|
|
|
|
/// @returns the values of the function output variables from _args at the point
|
|
|
|
/// where this summary was reached.
|
2020-10-19 11:21:05 +00:00
|
|
|
std::vector<std::optional<std::string>> summaryPostOutputValues(std::vector<smtutil::Expression> const& _args) const;
|
2020-08-20 08:43:50 +00:00
|
|
|
|
2021-01-21 18:04:34 +00:00
|
|
|
/// @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;
|
|
|
|
|
2021-10-06 09:48:15 +00:00
|
|
|
/// @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;
|
|
|
|
|
2020-08-13 12:00:33 +00:00
|
|
|
private:
|
2020-10-19 11:21:05 +00:00
|
|
|
/// @returns the formatted version of the given SMT expressions. Those expressions must be SMT constants.
|
2021-03-22 16:12:05 +00:00
|
|
|
std::vector<std::optional<std::string>> formatExpressions(std::vector<smtutil::Expression> const& _exprs, std::vector<Type const*> const& _types) const;
|
2020-10-19 11:21:05 +00:00
|
|
|
|
|
|
|
/// @returns a string representation of the SMT expression based on a Solidity type.
|
2021-03-22 16:12:05 +00:00
|
|
|
std::optional<std::string> expressionToString(smtutil::Expression const& _expr, Type const* _type) const;
|
2020-10-19 11:21:05 +00:00
|
|
|
|
2020-10-19 15:13:21 +00:00
|
|
|
/// Recursively fills _array from _expr.
|
|
|
|
/// _expr should have the form `store(store(...(const_array(x_0), i_0, e_0), i_m, e_m), i_k, e_k)`.
|
|
|
|
/// @returns true if the construction worked,
|
|
|
|
/// and false if at least one element could not be built.
|
|
|
|
bool fillArray(smtutil::Expression const& _expr, std::vector<std::string>& _array, ArrayType const& _type) const;
|
|
|
|
|
2021-01-20 10:22:28 +00:00
|
|
|
std::map<std::string, std::optional<std::string>> readTxVars(smtutil::Expression const& _tx) const;
|
|
|
|
|
2020-08-13 12:00:33 +00:00
|
|
|
/// The actual SMT expression.
|
|
|
|
smt::SymbolicFunctionVariable m_predicate;
|
|
|
|
|
2020-09-16 09:47:54 +00:00
|
|
|
/// The type of this predicate.
|
|
|
|
PredicateType m_type;
|
|
|
|
|
2020-08-13 12:00:33 +00:00
|
|
|
/// The ASTNode that this predicate represents.
|
|
|
|
/// nullptr if this predicate is not associated with a specific program AST node.
|
|
|
|
ASTNode const* m_node = nullptr;
|
|
|
|
|
2021-01-22 10:42:40 +00:00
|
|
|
/// The ContractDefinition that contains this predicate.
|
|
|
|
/// nullptr if this predicate is not associated with a specific contract.
|
|
|
|
/// This is unfortunately necessary because of virtual resolution for
|
|
|
|
/// function nodes.
|
|
|
|
ContractDefinition const* m_contractContext = nullptr;
|
|
|
|
|
2020-08-13 12:00:33 +00:00
|
|
|
/// Maps the name of the predicate to the actual Predicate.
|
|
|
|
/// Used in counterexample generation.
|
|
|
|
static std::map<std::string, Predicate> m_predicates;
|
2021-01-21 18:04:34 +00:00
|
|
|
|
|
|
|
/// The scope stack when the predicate was created.
|
|
|
|
/// Used to identify the subset of variables in scope.
|
|
|
|
std::vector<ScopeOpener const*> const m_scopeStack;
|
2020-08-13 12:00:33 +00:00
|
|
|
};
|
|
|
|
|
2021-10-06 09:48:15 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-08-13 12:00:33 +00:00
|
|
|
}
|