Rename local variable in case of re-definition (fix #151)

It is a temporary fix, a long term solution requires to implement a correct local variables scoping
pull/169/head
Josselin 6 years ago
parent e545eaab37
commit f3992c354d
  1. 35
      slither/solc_parsing/declarations/function.py
  2. 5
      slither/solc_parsing/expressions/expression_parsing.py
  3. 17
      slither/solc_parsing/variables/variable_declaration.py

@ -48,6 +48,15 @@ class FunctionSolc(Function):
self._content_was_analyzed = False self._content_was_analyzed = False
self._counter_nodes = 0 self._counter_nodes = 0
self._counter_scope_local_variables = 0
# variable renamed will map the solc id
# to the variable. It only works for compact format
# Later if an expression provides the referencedDeclaration attr
# we can retrieve the variable
# It only matters if two variables have the same name in the function
# which is only possible with solc > 0.5
self._variables_renamed = {}
def get_key(self): def get_key(self):
return self.slither.get_key() return self.slither.get_key()
@ -60,6 +69,24 @@ class FunctionSolc(Function):
def is_compact_ast(self): def is_compact_ast(self):
return self.slither.is_compact_ast return self.slither.is_compact_ast
@property
def variables_renamed(self):
return self._variables_renamed
def _add_local_variable(self, local_var):
# If two local variables have the same name
# We add a suffix to the new variable
# This is done to prevent collision during SSA translation
# Use of while in case of collision
# In the worst case, the name will be really long
while local_var.name in self._variables:
local_var.name += "_scope_{}".format(self._counter_scope_local_variables)
self._counter_scope_local_variables += 1
if not local_var.reference_id is None:
self._variables_renamed[local_var.reference_id] = local_var
self._variables[local_var.name] = local_var
def _analyze_attributes(self): def _analyze_attributes(self):
if self.is_compact_ast: if self.is_compact_ast:
attributes = self._functionNotParsed attributes = self._functionNotParsed
@ -329,7 +356,7 @@ class FunctionSolc(Function):
local_var.set_function(self) local_var.set_function(self)
local_var.set_offset(statement['src'], self.contract.slither) local_var.set_offset(statement['src'], self.contract.slither)
self._variables[local_var.name] = local_var self._add_local_variable(local_var)
#local_var.analyze(self) #local_var.analyze(self)
new_node = self._new_node(NodeType.VARIABLE, statement['src']) new_node = self._new_node(NodeType.VARIABLE, statement['src'])
@ -491,7 +518,7 @@ class FunctionSolc(Function):
local_var.set_function(self) local_var.set_function(self)
local_var.set_offset(statement['src'], self.contract.slither) local_var.set_offset(statement['src'], self.contract.slither)
self._variables[local_var.name] = local_var self._add_local_variable(local_var)
# local_var.analyze(self) # local_var.analyze(self)
new_node = self._new_node(NodeType.VARIABLE, statement['src']) new_node = self._new_node(NodeType.VARIABLE, statement['src'])
@ -741,7 +768,7 @@ class FunctionSolc(Function):
if local_var.location == 'default': if local_var.location == 'default':
local_var.set_location('memory') local_var.set_location('memory')
self._variables[local_var.name] = local_var self._add_local_variable(local_var)
self._parameters.append(local_var) self._parameters.append(local_var)
def _parse_returns(self, returns): def _parse_returns(self, returns):
@ -766,7 +793,7 @@ class FunctionSolc(Function):
if local_var.location == 'default': if local_var.location == 'default':
local_var.set_location('memory') local_var.set_location('memory')
self._variables[local_var.name] = local_var self._add_local_variable(local_var)
self._returns.append(local_var) self._returns.append(local_var)

@ -60,6 +60,11 @@ def find_variable(var_name, caller_context, referenced_declaration=None):
exit(-1) exit(-1)
if function: if function:
# We look for variable declared with the referencedDeclaration attr
func_variables = function.variables_renamed
if referenced_declaration and referenced_declaration in func_variables:
return func_variables[referenced_declaration]
# If not found, check for name
func_variables = function.variables_as_dict() func_variables = function.variables_as_dict()
if var_name in func_variables: if var_name in func_variables:
return func_variables[var_name] return func_variables[var_name]

@ -35,6 +35,9 @@ class VariableDeclarationSolc(Variable):
self._is_compact_ast = False self._is_compact_ast = False
self._reference_id = None
if 'nodeType' in var: if 'nodeType' in var:
self._is_compact_ast = True self._is_compact_ast = True
nodeType = var['nodeType'] nodeType = var['nodeType']
@ -80,6 +83,14 @@ class VariableDeclarationSolc(Variable):
def uninitialized(self): def uninitialized(self):
return not self._initialized return not self._initialized
@property
def reference_id(self):
'''
Return the solc id. It can be compared with the referencedDeclaration attr
Returns None if it was not parsed (legacy AST)
'''
return self._reference_id
def _analyze_variable_attributes(self, attributes): def _analyze_variable_attributes(self, attributes):
if 'visibility' in attributes: if 'visibility' in attributes:
self._visibility = attributes['visibility'] self._visibility = attributes['visibility']
@ -105,6 +116,12 @@ class VariableDeclarationSolc(Variable):
self._initial_expression = None self._initial_expression = None
self._type = None self._type = None
# Only for comapct ast format
# the id can be used later if referencedDeclaration
# is provided
if 'id' in var:
self._reference_id = var['id']
if 'constant' in attributes: if 'constant' in attributes:
self._is_constant = attributes['constant'] self._is_constant = attributes['constant']

Loading…
Cancel
Save