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
# include <libsolidity/formal/Predicate.h>
2020-08-19 11:53:16 +00:00
# include <libsolidity/formal/SMTEncoder.h>
2020-08-13 12:00:33 +00:00
# include <libsolidity/ast/AST.h>
# include <boost/algorithm/string/join.hpp>
# include <utility>
using namespace std ;
using namespace solidity ;
using namespace solidity : : smtutil ;
using namespace solidity : : frontend ;
using namespace solidity : : frontend : : smt ;
map < string , Predicate > Predicate : : m_predicates ;
Predicate const * Predicate : : create (
SortPointer _sort ,
string _name ,
2020-09-16 09:47:54 +00:00
PredicateType _type ,
2020-08-13 12:00:33 +00:00
EncodingContext & _context ,
ASTNode const * _node
)
{
smt : : SymbolicFunctionVariable predicate { _sort , move ( _name ) , _context } ;
string functorName = predicate . currentName ( ) ;
solAssert ( ! m_predicates . count ( functorName ) , " " ) ;
return & m_predicates . emplace (
std : : piecewise_construct ,
std : : forward_as_tuple ( functorName ) ,
2020-09-16 09:47:54 +00:00
std : : forward_as_tuple ( move ( predicate ) , _type , _node )
2020-08-13 12:00:33 +00:00
) . first - > second ;
}
Predicate : : Predicate (
smt : : SymbolicFunctionVariable & & _predicate ,
2020-09-16 09:47:54 +00:00
PredicateType _type ,
2020-08-13 12:00:33 +00:00
ASTNode const * _node
) :
m_predicate ( move ( _predicate ) ) ,
2020-09-16 09:47:54 +00:00
m_type ( _type ) ,
2020-08-13 12:00:33 +00:00
m_node ( _node )
{
}
Predicate const * Predicate : : predicate ( string const & _name )
{
return & m_predicates . at ( _name ) ;
}
void Predicate : : reset ( )
{
m_predicates . clear ( ) ;
}
smtutil : : Expression Predicate : : operator ( ) ( vector < smtutil : : Expression > const & _args ) const
{
return m_predicate ( _args ) ;
}
smtutil : : Expression Predicate : : functor ( ) const
{
return m_predicate . currentFunctionValue ( ) ;
}
smtutil : : Expression Predicate : : functor ( unsigned _idx ) const
{
return m_predicate . functionValueAtIndex ( _idx ) ;
}
void Predicate : : newFunctor ( )
{
m_predicate . increaseIndex ( ) ;
}
2020-08-19 11:53:16 +00:00
ASTNode const * Predicate : : programNode ( ) const
{
2020-08-13 12:00:33 +00:00
return m_node ;
}
2020-08-19 11:53:16 +00:00
ContractDefinition const * Predicate : : programContract ( ) const
{
if ( auto const * contract = dynamic_cast < ContractDefinition const * > ( m_node ) )
if ( ! contract - > constructor ( ) )
return contract ;
return nullptr ;
}
FunctionDefinition const * Predicate : : programFunction ( ) const
{
if ( auto const * contract = dynamic_cast < ContractDefinition const * > ( m_node ) )
{
if ( contract - > constructor ( ) )
return contract - > constructor ( ) ;
return nullptr ;
}
if ( auto const * fun = dynamic_cast < FunctionDefinition const * > ( m_node ) )
return fun ;
return nullptr ;
}
optional < vector < VariableDeclaration const * > > Predicate : : stateVariables ( ) const
{
if ( auto const * fun = programFunction ( ) )
return SMTEncoder : : stateVariablesIncludingInheritedAndPrivate ( * fun ) ;
if ( auto const * contract = programContract ( ) )
return SMTEncoder : : stateVariablesIncludingInheritedAndPrivate ( * contract ) ;
auto const * node = m_node ;
while ( auto const * scopable = dynamic_cast < Scopable const * > ( node ) )
{
node = scopable - > scope ( ) ;
if ( auto const * fun = dynamic_cast < FunctionDefinition const * > ( node ) )
return SMTEncoder : : stateVariablesIncludingInheritedAndPrivate ( * fun ) ;
}
return nullopt ;
}
bool Predicate : : isSummary ( ) const
{
return functor ( ) . name . rfind ( " summary " , 0 ) = = 0 ;
}
bool Predicate : : isInterface ( ) const
{
return functor ( ) . name . rfind ( " interface " , 0 ) = = 0 ;
}
2020-10-19 11:21:05 +00:00
string Predicate : : formatSummaryCall ( vector < smtutil : : Expression > const & _args ) const
2020-08-19 11:53:16 +00:00
{
if ( programContract ( ) )
return " constructor() " ;
solAssert ( isSummary ( ) , " " ) ;
auto stateVars = stateVariables ( ) ;
solAssert ( stateVars . has_value ( ) , " " ) ;
auto const * fun = programFunction ( ) ;
solAssert ( fun , " " ) ;
2020-10-13 16:00:26 +00:00
/// The signature of a function summary predicate is: summary(error, this, cryptoFunctions, txData, preBlockChainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
2020-08-19 11:53:16 +00:00
/// Here we are interested in preInputVars.
2020-10-19 11:21:05 +00:00
auto first = _args . begin ( ) + 5 + static_cast < int > ( stateVars - > size ( ) ) ;
auto last = first + static_cast < int > ( fun - > parameters ( ) . size ( ) ) ;
2020-08-19 11:53:16 +00:00
solAssert ( first > = _args . begin ( ) & & first < = _args . end ( ) , " " ) ;
solAssert ( last > = _args . begin ( ) & & last < = _args . end ( ) , " " ) ;
2020-10-19 11:21:05 +00:00
auto inTypes = FunctionType ( * fun ) . parameterTypes ( ) ;
vector < optional < string > > functionArgsCex = formatExpressions ( vector < smtutil : : Expression > ( first , last ) , inTypes ) ;
2020-08-19 11:53:16 +00:00
vector < string > functionArgs ;
auto const & params = fun - > parameters ( ) ;
solAssert ( params . size ( ) = = functionArgsCex . size ( ) , " " ) ;
for ( unsigned i = 0 ; i < params . size ( ) ; + + i )
if ( params [ i ] - > type ( ) - > isValueType ( ) )
2020-10-19 11:21:05 +00:00
{
solAssert ( functionArgsCex . at ( i ) , " " ) ;
functionArgs . emplace_back ( * functionArgsCex . at ( i ) ) ;
}
2020-08-19 11:53:16 +00:00
else
functionArgs . emplace_back ( params [ i ] - > name ( ) ) ;
string fName = fun - > isConstructor ( ) ? " constructor " :
fun - > isFallback ( ) ? " fallback " :
fun - > isReceive ( ) ? " receive " :
fun - > name ( ) ;
return fName + " ( " + boost : : algorithm : : join ( functionArgs , " , " ) + " ) " ;
}
2020-08-19 16:38:56 +00:00
2020-10-19 11:21:05 +00:00
vector < optional < string > > Predicate : : summaryStateValues ( vector < smtutil : : Expression > const & _args ) const
2020-08-19 16:38:56 +00:00
{
2020-10-13 16:00:26 +00:00
/// The signature of a function summary predicate is: summary(error, this, cryptoFunctions, txData, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
/// The signature of an implicit constructor summary predicate is: summary(error, this, cryptoFunctions, txData, preBlockchainState, postBlockchainState, postStateVars).
2020-08-19 16:38:56 +00:00
/// Here we are interested in postStateVars.
auto stateVars = stateVariables ( ) ;
solAssert ( stateVars . has_value ( ) , " " ) ;
2020-10-19 11:21:05 +00:00
vector < smtutil : : Expression > : : const_iterator stateFirst ;
vector < smtutil : : Expression > : : const_iterator stateLast ;
2020-08-19 16:38:56 +00:00
if ( auto const * function = programFunction ( ) )
{
2020-10-13 16:00:26 +00:00
stateFirst = _args . begin ( ) + 5 + static_cast < int > ( stateVars - > size ( ) ) + static_cast < int > ( function - > parameters ( ) . size ( ) ) + 1 ;
2020-08-19 16:38:56 +00:00
stateLast = stateFirst + static_cast < int > ( stateVars - > size ( ) ) ;
}
else if ( programContract ( ) )
{
2020-10-13 16:00:26 +00:00
stateFirst = _args . begin ( ) + 6 ;
2020-08-19 16:38:56 +00:00
stateLast = stateFirst + static_cast < int > ( stateVars - > size ( ) ) ;
}
else
solAssert ( false , " " ) ;
solAssert ( stateFirst > = _args . begin ( ) & & stateFirst < = _args . end ( ) , " " ) ;
solAssert ( stateLast > = _args . begin ( ) & & stateLast < = _args . end ( ) , " " ) ;
2020-10-19 11:21:05 +00:00
vector < smtutil : : Expression > stateArgs ( stateFirst , stateLast ) ;
2020-08-19 16:38:56 +00:00
solAssert ( stateArgs . size ( ) = = stateVars - > size ( ) , " " ) ;
2020-10-19 11:21:05 +00:00
auto stateTypes = applyMap ( * stateVars , [ & ] ( auto const & _var ) { return _var - > type ( ) ; } ) ;
return formatExpressions ( stateArgs , stateTypes ) ;
2020-08-19 16:38:56 +00:00
}
2020-08-20 08:43:50 +00:00
2020-10-19 11:21:05 +00:00
vector < optional < string > > Predicate : : summaryPostInputValues ( vector < smtutil : : Expression > const & _args ) const
2020-08-20 08:43:50 +00:00
{
2020-10-13 16:00:26 +00:00
/// The signature of a function summary predicate is: summary(error, this, cryptoFunctions, txData, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
2020-08-20 08:43:50 +00:00
/// Here we are interested in postInputVars.
auto const * function = programFunction ( ) ;
solAssert ( function , " " ) ;
auto stateVars = stateVariables ( ) ;
solAssert ( stateVars . has_value ( ) , " " ) ;
auto const & inParams = function - > parameters ( ) ;
2020-10-19 11:21:05 +00:00
auto first = _args . begin ( ) + 5 + static_cast < int > ( stateVars - > size ( ) ) * 2 + static_cast < int > ( inParams . size ( ) ) + 1 ;
auto last = first + static_cast < int > ( inParams . size ( ) ) ;
2020-08-20 08:43:50 +00:00
solAssert ( first > = _args . begin ( ) & & first < = _args . end ( ) , " " ) ;
solAssert ( last > = _args . begin ( ) & & last < = _args . end ( ) , " " ) ;
2020-10-19 11:21:05 +00:00
vector < smtutil : : Expression > inValues ( first , last ) ;
2020-08-20 08:43:50 +00:00
solAssert ( inValues . size ( ) = = inParams . size ( ) , " " ) ;
2020-10-19 11:21:05 +00:00
auto inTypes = FunctionType ( * function ) . parameterTypes ( ) ;
return formatExpressions ( inValues , inTypes ) ;
2020-08-20 08:43:50 +00:00
}
2020-10-19 11:21:05 +00:00
vector < optional < string > > Predicate : : summaryPostOutputValues ( vector < smtutil : : Expression > const & _args ) const
2020-08-20 08:43:50 +00:00
{
2020-10-13 16:00:26 +00:00
/// The signature of a function summary predicate is: summary(error, this, cryptoFunctions, txData, preBlockchainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars).
2020-08-20 08:43:50 +00:00
/// Here we are interested in outputVars.
auto const * function = programFunction ( ) ;
solAssert ( function , " " ) ;
auto stateVars = stateVariables ( ) ;
solAssert ( stateVars . has_value ( ) , " " ) ;
auto const & inParams = function - > parameters ( ) ;
2020-10-19 11:21:05 +00:00
auto first = _args . begin ( ) + 5 + static_cast < int > ( stateVars - > size ( ) ) * 2 + static_cast < int > ( inParams . size ( ) ) * 2 + 1 ;
2020-08-20 08:43:50 +00:00
solAssert ( first > = _args . begin ( ) & & first < = _args . end ( ) , " " ) ;
2020-10-19 11:21:05 +00:00
vector < smtutil : : Expression > outValues ( first , _args . end ( ) ) ;
2020-08-20 08:43:50 +00:00
solAssert ( outValues . size ( ) = = function - > returnParameters ( ) . size ( ) , " " ) ;
2020-10-19 11:21:05 +00:00
auto outTypes = FunctionType ( * function ) . returnParameterTypes ( ) ;
return formatExpressions ( outValues , outTypes ) ;
}
vector < optional < string > > Predicate : : formatExpressions ( vector < smtutil : : Expression > const & _exprs , vector < TypePointer > const & _types ) const
{
solAssert ( _exprs . size ( ) = = _types . size ( ) , " " ) ;
vector < optional < string > > strExprs ;
for ( unsigned i = 0 ; i < _exprs . size ( ) ; + + i )
strExprs . push_back ( expressionToString ( _exprs . at ( i ) , _types . at ( i ) ) ) ;
return strExprs ;
}
optional < string > Predicate : : expressionToString ( smtutil : : Expression const & _expr , TypePointer _type ) const
{
if ( smt : : isNumber ( * _type ) )
{
solAssert ( _expr . sort - > kind = = Kind : : Int , " " ) ;
solAssert ( _expr . arguments . empty ( ) , " " ) ;
// TODO assert that _expr.name is a number.
return _expr . name ;
}
if ( smt : : isBool ( * _type ) )
{
solAssert ( _expr . sort - > kind = = Kind : : Bool , " " ) ;
solAssert ( _expr . arguments . empty ( ) , " " ) ;
solAssert ( _expr . name = = " true " | | _expr . name = = " false " , " " ) ;
return _expr . name ;
}
if ( smt : : isFunction ( * _type ) )
{
solAssert ( _expr . arguments . empty ( ) , " " ) ;
return _expr . name ;
}
return { } ;
2020-08-20 08:43:50 +00:00
}