Add support for try/catch statements

pull/415/head
Josselin 5 years ago
parent 97bd577c3f
commit 73ece898ea
  1. 35
      slither/core/cfg/node.py
  2. 33
      slither/solc_parsing/declarations/contract.py
  3. 97
      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))

@ -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

@ -494,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)
@ -753,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
@ -865,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'
@ -878,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'
@ -906,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)
@ -973,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