/* 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 . */ // SPDX-License-Identifier: GPL-3.0 /** * Model checker based on Constrained Horn Clauses. * * A Solidity contract's CFG is encoded into a system of Horn clauses where * each block has a predicate and edges are rules. * * The entry block is the constructor which has no in-edges. * The constructor has one out-edge to an artificial block named _Interface_ * which has in/out-edges from/to all public functions. * * Loop invariants for Interface -> Interface' are state invariants. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace solidity::frontend { class CHC: public SMTEncoder { public: CHC( smt::EncodingContext& _context, langutil::UniqueErrorReporter& _errorReporter, langutil::UniqueErrorReporter& _unsupportedErrorReporter, std::map const& _smtlib2Responses, ReadCallback::Callback const& _smtCallback, ModelCheckerSettings _settings, langutil::CharStreamProvider const& _charStreamProvider ); void analyze(SourceUnit const& _sources); struct CHCVerificationTarget: VerificationTarget { unsigned const errorId; ASTNode const* const errorNode; friend bool operator<(CHCVerificationTarget const& _a, CHCVerificationTarget const& _b) { return _a.errorId < _b.errorId; } }; struct ReportTargetInfo { langutil::ErrorId error; langutil::SourceLocation location; std::string message; }; std::map, smt::EncodingContext::IdCompare> const& safeTargets() const { return m_safeTargets; } std::map, smt::EncodingContext::IdCompare> const& unsafeTargets() const { return m_unsafeTargets; } /// This is used if the Horn solver is not directly linked into this binary. /// @returns a list of inputs to the Horn solver that were not part of the argument to /// the constructor. std::vector unhandledQueries() const; enum class CHCNatspecOption { AbstractFunctionNondet }; private: /// Visitor functions. //@{ bool visit(ContractDefinition const& _node) override; void endVisit(ContractDefinition const& _node) override; bool visit(FunctionDefinition const& _node) override; void endVisit(FunctionDefinition const& _node) override; bool visit(Block const& _block) override; void endVisit(Block const& _block) override; bool visit(IfStatement const& _node) override; bool visit(WhileStatement const&) override; bool visit(ForStatement const&) override; void endVisit(ForStatement const&) override; void endVisit(FunctionCall const& _node) override; void endVisit(Break const& _node) override; void endVisit(Continue const& _node) override; void endVisit(IndexRangeAccess const& _node) override; void endVisit(Return const& _node) override; bool visit(TryCatchClause const&) override; void endVisit(TryCatchClause const&) override; bool visit(TryStatement const& _node) override; void pushInlineFrame(CallableDeclaration const& _callable) override; void popInlineFrame(CallableDeclaration const& _callable) override; void visitAssert(FunctionCall const& _funCall); void visitPublicGetter(FunctionCall const& _funCall) override; void visitAddMulMod(FunctionCall const& _funCall) override; void visitDeployment(FunctionCall const& _funCall); void internalFunctionCall(FunctionCall const& _funCall); void externalFunctionCall(FunctionCall const& _funCall); void externalFunctionCallToTrustedCode(FunctionCall const& _funCall); void addNondetCalls(ContractDefinition const& _contract); void nondetCall(ContractDefinition const& _contract, VariableDeclaration const& _var); void unknownFunctionCall(FunctionCall const& _funCall); void makeArrayPopVerificationTarget(FunctionCall const& _arrayPop) override; void makeOutOfBoundsVerificationTarget(IndexAccess const& _access) override; /// Creates underflow/overflow verification targets. std::pair arithmeticOperation( Token _op, smtutil::Expression const& _left, smtutil::Expression const& _right, Type const* _commonType, Expression const& _expression ) override; //@} /// Helpers. //@{ void resetSourceAnalysis(); void resetContractAnalysis(); void eraseKnowledge(); void clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function = nullptr) override; void setCurrentBlock(Predicate const& _block); std::set transactionVerificationTargetsIds(ASTNode const* _txRoot); bool usesStaticCall(FunctionCall const& _funCall); //@} /// SMT Natspec and abstraction helpers. //@{ /// @returns a CHCNatspecOption enum if _option is a valid SMTChecker Natspec value /// or nullopt otherwise. static std::optional natspecOptionFromString(std::string const& _option); /// @returns which SMTChecker options are enabled by @a _function's Natspec via /// `@custom:smtchecker