Merge branch 'dev' into dev-fix-constructor

pull/416/head
Josselin 5 years ago
commit ce878aff8b
  1. 35
      slither/core/cfg/node.py
  2. 7
      slither/core/declarations/function.py
  3. 33
      slither/solc_parsing/declarations/contract.py
  4. 132
      slither/solc_parsing/declarations/function.py

@ -62,6 +62,9 @@ class NodeType:
# Only modifier node
PLACEHOLDER = 0x40
TRY = 0x41
CATCH = 0x42
# Node not related to the CFG
# Use for state variable declaration
OTHER_ENTRYPOINT = 0x50
@ -69,33 +72,37 @@ class NodeType:
# @staticmethod
def str(t):
if t == 0x0:
if t == NodeType.ENTRYPOINT:
return 'ENTRY_POINT'
if t == 0x10:
if t == NodeType.EXPRESSION:
return 'EXPRESSION'
if t == 0x11:
if t == NodeType.RETURN:
return 'RETURN'
if t == 0x12:
if t == NodeType.IF:
return 'IF'
if t == 0x13:
if t == NodeType.VARIABLE:
return 'NEW VARIABLE'
if t == 0x14:
if t == NodeType.ASSEMBLY:
return 'INLINE ASM'
if t == 0x15:
if t == NodeType.IFLOOP:
return 'IF_LOOP'
if t == 0x20:
if t == NodeType.THROW:
return 'THROW'
if t == 0x31:
if t == NodeType.BREAK:
return 'BREAK'
if t == 0x32:
if t == NodeType.CONTINUE:
return 'CONTINUE'
if t == 0x40:
if t == NodeType.PLACEHOLDER:
return '_'
if t == 0x50:
if t == NodeType.TRY:
return 'TRY'
if t == NodeType.CATCH:
return 'CATCH'
if t == NodeType.ENDIF:
return 'END_IF'
if t == 0x51:
if t == NodeType.STARTLOOP:
return 'BEGIN_LOOP'
if t == 0x52:
if t == NodeType.ENDLOOP:
return 'END_LOOP'
return 'Unknown type {}'.format(hex(t))

@ -54,8 +54,9 @@ class FunctionType(Enum):
NORMAL = 0
CONSTRUCTOR = 1
FALLBACK = 2
CONSTRUCTOR_VARIABLES = 3 # Fake function to hold variable declaration statements
CONSTRUCTOR_CONSTANT_VARIABLES = 4 # Fake function to hold variable declaration statements
RECEIVE = 3
CONSTRUCTOR_VARIABLES = 10 # Fake function to hold variable declaration statements
CONSTRUCTOR_CONSTANT_VARIABLES = 11 # Fake function to hold variable declaration statements
class Function(ChildContract, ChildInheritance, SourceMapping):
"""
@ -156,6 +157,8 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
return 'constructor'
elif self._function_type == FunctionType.FALLBACK:
return 'fallback'
elif self._function_type == FunctionType.RECEIVE:
return 'receive'
elif self._function_type == FunctionType.CONSTRUCTOR_VARIABLES:
return 'slitherConstructorVariables'
elif self._function_type == FunctionType.CONSTRUCTOR_CONSTANT_VARIABLES:

@ -280,7 +280,8 @@ class ContractSolc04(Contract):
try:
for modifier in self.modifiers:
modifier.analyze_content()
except (VariableNotFound, KeyError):
except (VariableNotFound, KeyError) as e:
logger.error(e)
self.log_incorrect_parsing()
return
@ -288,7 +289,8 @@ class ContractSolc04(Contract):
try:
for function in self.functions:
function.analyze_content()
except (VariableNotFound, KeyError):
except (VariableNotFound, KeyError) as e:
logger.error(e)
self.log_incorrect_parsing()
return
@ -300,7 +302,8 @@ class ContractSolc04(Contract):
getter_available = lambda f: f.modifiers_declared
Cls = ModifierSolc
self._modifiers = self._analyze_params_elements(elements_no_params, getter, getter_available, Cls)
except (VariableNotFound, KeyError):
except (VariableNotFound, KeyError) as e:
logger.error(e)
self.log_incorrect_parsing()
self._modifiers_no_params = []
@ -313,7 +316,8 @@ class ContractSolc04(Contract):
getter_available = lambda f: f.functions_declared
Cls = FunctionSolc
self._functions = self._analyze_params_elements(elements_no_params, getter, getter_available, Cls)
except (VariableNotFound, KeyError):
except (VariableNotFound, KeyError) as e:
logger.error(e)
self.log_incorrect_parsing()
self._functions_no_params = []
return
@ -364,7 +368,8 @@ class ContractSolc04(Contract):
if accessible_elements[element.full_name] != all_elements[element.canonical_name]:
element.is_shadowed = True
accessible_elements[element.full_name].shadows = True
except (VariableNotFound, KeyError):
except (VariableNotFound, KeyError) as e:
logger.error(e)
self.log_incorrect_parsing()
return all_elements
@ -374,7 +379,8 @@ class ContractSolc04(Contract):
# cant parse constant expression based on function calls
try:
var.analyze(self)
except (VariableNotFound, KeyError):
except (VariableNotFound, KeyError) as e:
logger.error(e)
pass
return
@ -451,7 +457,8 @@ class ContractSolc04(Contract):
for var in self.variables:
var.analyze(self)
return
except (VariableNotFound, KeyError):
except (VariableNotFound, KeyError) as e:
logger.error(e)
self.log_incorrect_parsing()
def analyze_using_for(self):
@ -483,7 +490,8 @@ class ContractSolc04(Contract):
self.using_for[old] = []
self._using_for[old].append(new)
self._usingForNotParsed = []
except (VariableNotFound, KeyError):
except (VariableNotFound, KeyError) as e:
logger.error(e)
self.log_incorrect_parsing()
def analyze_enums(self):
@ -496,7 +504,8 @@ class ContractSolc04(Contract):
# at the same time
self._analyze_enum(enum)
self._enumsNotParsed = None
except (VariableNotFound, KeyError):
except (VariableNotFound, KeyError) as e:
logger.error(e)
self.log_incorrect_parsing()
def _analyze_enum(self, enum):
@ -530,7 +539,8 @@ class ContractSolc04(Contract):
try:
for struct in self.structures:
self._analyze_struct(struct)
except (VariableNotFound, KeyError):
except (VariableNotFound, KeyError) as e:
logger.error(e)
self.log_incorrect_parsing()
def analyze_events(self):
@ -544,7 +554,8 @@ class ContractSolc04(Contract):
event.set_contract(self)
event.set_offset(event_to_parse['src'], self.slither)
self._events[event.full_name] = event
except (VariableNotFound, KeyError):
except (VariableNotFound, KeyError) as e:
logger.error(e)
self.log_incorrect_parsing()
self._eventsNotParsed = None

@ -56,6 +56,8 @@ class FunctionSolc(Function):
# which is only possible with solc > 0.5
self._variables_renamed = {}
self._analyze_type()
###################################################################################
###################################################################################
# region AST format
@ -113,6 +115,31 @@ class FunctionSolc(Function):
###################################################################################
###################################################################################
def _analyze_type(self):
"""
Analyz the type of the function
Myst be called in the constructor as the name might change according to the function's type
For example both the fallback and the receiver will have an empty name
:return:
"""
if self.is_compact_ast:
attributes = self._functionNotParsed
else:
attributes = self._functionNotParsed['attributes']
if self._name == '':
self._function_type = FunctionType.FALLBACK
# 0.6.x introduced the receiver function
# It has also an empty name, so we need to check the kind attribute
if 'kind' in attributes:
if attributes['kind'] == 'receive':
self._function_type = FunctionType.RECEIVE
else:
self._function_type = FunctionType.NORMAL
if self._name == self.contract_declarer.name:
self._function_type = FunctionType.CONSTRUCTOR
def _analyze_attributes(self):
if self.is_compact_ast:
attributes = self._functionNotParsed
@ -133,14 +160,6 @@ class FunctionSolc(Function):
if 'constant' in attributes:
self._view = attributes['constant']
if self._name == '':
self._function_type = FunctionType.FALLBACK
else:
self._function_type = FunctionType.NORMAL
if self._name == self.contract_declarer.name:
self._function_type = FunctionType.CONSTRUCTOR
if 'isConstructor' in attributes and attributes['isConstructor']:
self._function_type = FunctionType.CONSTRUCTOR
@ -475,6 +494,39 @@ class FunctionSolc(Function):
link_nodes(node_condition, node_endDoWhile)
return node_endDoWhile
def _parse_try_catch(self, statement, node):
externalCall = statement.get('externalCall', None)
if externalCall is None:
raise ParsingError('Try/Catch not correctly parsed by Slither %s' % statement)
new_node = self._new_node(NodeType.TRY, statement['src'])
new_node.add_unparsed_expression(externalCall)
link_nodes(node, new_node)
node = new_node
for clause in statement.get('clauses', []):
self._parse_catch(clause, node)
return node
def _parse_catch(self, statement, node):
block = statement.get('block', None)
if block is None:
raise ParsingError('Catch not correctly parsed by Slither %s' % statement)
try_node = self._new_node(NodeType.CATCH, statement['src'])
link_nodes(node, try_node)
if self.is_compact_ast:
params = statement['parameters']
else:
params = statement[self.get_children('children')]
for param in params.get('parameters', []):
assert param[self.get_key()] == 'VariableDeclaration'
self._add_param(param)
return self._parse_statement(block, try_node)
def _parse_variable_definition(self, statement, node):
try:
local_var = LocalVariableSolc(statement)
@ -734,8 +786,12 @@ class FunctionSolc(Function):
new_node.add_unparsed_expression(expression)
link_nodes(node, new_node)
node = new_node
elif name == 'TryStatement':
node = self._parse_try_catch(statement, node)
# elif name == 'TryCatchClause':
# self._parse_catch(statement, node)
else:
raise ParsingError('Statement not parsed %s'%name)
raise ParsingError('Statement not parsed %s' % name)
return node
@ -846,6 +902,35 @@ class FunctionSolc(Function):
node.set_sons([start_node])
start_node.add_father(node)
def _fix_try(self, node):
end_node = next((son for son in node.sons if son.type != NodeType.CATCH), None)
if end_node:
for son in node.sons:
if son.type == NodeType.CATCH:
self._fix_catch(son, end_node)
def _fix_catch(self, node, end_node):
if not node.sons:
link_nodes(node, end_node)
else:
for son in node.sons:
self._fix_catch(son, end_node)
def _add_param(self, param):
local_var = LocalVariableSolc(param)
local_var.set_function(self)
local_var.set_offset(param['src'], self.contract.slither)
local_var.analyze(self)
# see https://solidity.readthedocs.io/en/v0.4.24/types.html?highlight=storage%20location#data-location
if local_var.location == 'default':
local_var.set_location('memory')
self._add_local_variable(local_var)
return local_var
def _parse_params(self, params):
assert params[self.get_key()] == 'ParameterList'
@ -859,20 +944,10 @@ class FunctionSolc(Function):
for param in params:
assert param[self.get_key()] == 'VariableDeclaration'
local_var = LocalVariableSolc(param)
local_var.set_function(self)
local_var.set_offset(param['src'], self.contract.slither)
local_var.analyze(self)
# see https://solidity.readthedocs.io/en/v0.4.24/types.html?highlight=storage%20location#data-location
if local_var.location == 'default':
local_var.set_location('memory')
self._add_local_variable(local_var)
local_var = self._add_param(param)
self._parameters.append(local_var)
def _parse_returns(self, returns):
assert returns[self.get_key()] == 'ParameterList'
@ -887,18 +962,7 @@ class FunctionSolc(Function):
for ret in returns:
assert ret[self.get_key()] == 'VariableDeclaration'
local_var = LocalVariableSolc(ret)
local_var.set_function(self)
local_var.set_offset(ret['src'], self.contract.slither)
local_var.analyze(self)
# see https://solidity.readthedocs.io/en/v0.4.24/types.html?highlight=storage%20location#data-location
if local_var.location == 'default':
local_var.set_location('memory')
self._add_local_variable(local_var)
local_var = self._add_param(ret)
self._returns.append(local_var)
@ -954,6 +1018,8 @@ class FunctionSolc(Function):
self._fix_break_node(node)
if node.type in [NodeType.CONTINUE]:
self._fix_continue_node(node)
if node.type in [NodeType.TRY]:
self._fix_try(node)
def _remove_alone_endif(self):
"""

Loading…
Cancel
Save