|
|
@ -23,7 +23,8 @@ def format(slither, patches, elements): |
|
|
|
for element in elements: |
|
|
|
for element in elements: |
|
|
|
target = element['additional_fields']['target'] |
|
|
|
target = element['additional_fields']['target'] |
|
|
|
if (target == "parameter"): |
|
|
|
if (target == "parameter"): |
|
|
|
_patch(slither, patches, |
|
|
|
_patch(slither, |
|
|
|
|
|
|
|
patches, |
|
|
|
element['additional_fields']['target'], |
|
|
|
element['additional_fields']['target'], |
|
|
|
element['name'], |
|
|
|
element['name'], |
|
|
|
element['type_specific_fields']['parent']['name'], |
|
|
|
element['type_specific_fields']['parent']['name'], |
|
|
@ -36,16 +37,23 @@ def format(slither, patches, elements): |
|
|
|
elif target in ["modifier", "function", "event", |
|
|
|
elif target in ["modifier", "function", "event", |
|
|
|
"variable", "variable_constant", "enum" |
|
|
|
"variable", "variable_constant", "enum" |
|
|
|
"structure"]: |
|
|
|
"structure"]: |
|
|
|
_patch(slither, patches, target, |
|
|
|
_patch(slither, |
|
|
|
element['name'], element['name'], |
|
|
|
patches, |
|
|
|
|
|
|
|
target, |
|
|
|
|
|
|
|
element['name'], |
|
|
|
|
|
|
|
element['name'], |
|
|
|
element['type_specific_fields']['parent']['name'], |
|
|
|
element['type_specific_fields']['parent']['name'], |
|
|
|
element['source_mapping']['filename_absolute'], |
|
|
|
element['source_mapping']['filename_absolute'], |
|
|
|
element['source_mapping']['filename_relative'], |
|
|
|
element['source_mapping']['filename_relative'], |
|
|
|
element['source_mapping']['start'], |
|
|
|
element['source_mapping']['start'], |
|
|
|
(element['source_mapping']['start'] + element['source_mapping']['length'])) |
|
|
|
(element['source_mapping']['start'] + element['source_mapping']['length'])) |
|
|
|
else: |
|
|
|
else: |
|
|
|
_patch(slither, patches, element['additional_fields']['target'], |
|
|
|
_patch(slither, |
|
|
|
element['name'], element['name'], element['name'], |
|
|
|
patches, |
|
|
|
|
|
|
|
element['additional_fields']['target'], |
|
|
|
|
|
|
|
element['name'], |
|
|
|
|
|
|
|
element['name'], |
|
|
|
|
|
|
|
element['name'], |
|
|
|
element['source_mapping']['filename_absolute'], |
|
|
|
element['source_mapping']['filename_absolute'], |
|
|
|
element['source_mapping']['filename_relative'], |
|
|
|
element['source_mapping']['filename_relative'], |
|
|
|
element['source_mapping']['start'], |
|
|
|
element['source_mapping']['start'], |
|
|
@ -457,75 +465,74 @@ def _create_patch_parameter_uses(format_info): |
|
|
|
contract_name = format_info.contract_name |
|
|
|
contract_name = format_info.contract_name |
|
|
|
function_name = format_info.function_name |
|
|
|
function_name = format_info.function_name |
|
|
|
|
|
|
|
|
|
|
|
for contract in slither.contracts: |
|
|
|
target_contract = slither.get_contract_from_name(contract_name) |
|
|
|
if (contract.name == contract_name): |
|
|
|
for function in target_contract.functions: |
|
|
|
for function in contract.functions: |
|
|
|
if (function.name == function_name): |
|
|
|
if (function.name == function_name): |
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
for node in function.nodes: |
|
|
|
for node in function.nodes: |
|
|
|
vars = node._expression_vars_written + node._expression_vars_read |
|
|
|
vars = node._expression_vars_written + node._expression_vars_read |
|
|
|
for v in vars: |
|
|
|
for v in vars: |
|
|
|
if isinstance(v, Identifier) and str(v) == name and [str(lv) for lv in |
|
|
|
if isinstance(v, Identifier) and str(v) == name and [str(lv) for lv in |
|
|
|
(node._local_vars_read + |
|
|
|
(node._local_vars_read + |
|
|
|
node._local_vars_written) |
|
|
|
node._local_vars_written) |
|
|
|
if str(lv) == name]: |
|
|
|
if str(lv) == name]: |
|
|
|
modify_loc_start = int(v.source_mapping['start']) |
|
|
|
modify_loc_start = int(v.source_mapping['start']) |
|
|
|
modify_loc_end = int(v.source_mapping['start']) + int(v.source_mapping['length']) |
|
|
|
modify_loc_end = int(v.source_mapping['start']) + int(v.source_mapping['length']) |
|
|
|
old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end] |
|
|
|
old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end] |
|
|
|
if(name[0] == '_'): |
|
|
|
if(name[0] == '_'): |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+name+r'(.*)', |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+name+r'(.*)', |
|
|
|
r'\1'+name[0]+name[1].upper()+name[2:] + |
|
|
|
r'\1'+name[0]+name[1].upper()+name[2:] + |
|
|
|
r'\2', old_str_of_interest.decode('utf-8'), |
|
|
|
r'\2', old_str_of_interest.decode('utf-8'), |
|
|
|
1) |
|
|
|
1) |
|
|
|
else: |
|
|
|
else: |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+name+r'(.*)', r'\1'+'_' + |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+name+r'(.*)', r'\1'+'_' + |
|
|
|
name[0].upper()+name[1:]+r'\2', |
|
|
|
name[0].upper()+name[1:]+r'\2', |
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
if num_repl != 0: |
|
|
|
if num_repl != 0: |
|
|
|
patch = { |
|
|
|
patch = { |
|
|
|
"file" : in_file, |
|
|
|
"file" : in_file, |
|
|
|
"detector" : "naming-convention (parameter uses)", |
|
|
|
"detector" : "naming-convention (parameter uses)", |
|
|
|
"start" : modify_loc_start, |
|
|
|
"start" : modify_loc_start, |
|
|
|
"end" : modify_loc_end, |
|
|
|
"end" : modify_loc_end, |
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
"new_string" : new_str_of_interest |
|
|
|
"new_string" : new_str_of_interest |
|
|
|
} |
|
|
|
} |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
else: |
|
|
|
else: |
|
|
|
raise SlitherException("Could not find parameter use?!") |
|
|
|
raise SlitherException("Could not find parameter use?!") |
|
|
|
|
|
|
|
|
|
|
|
# Process function parameters passed to modifiers |
|
|
|
# Process function parameters passed to modifiers |
|
|
|
for modifier in function._expression_modifiers: |
|
|
|
for modifier in function._expression_modifiers: |
|
|
|
for arg in modifier.arguments: |
|
|
|
for arg in modifier.arguments: |
|
|
|
if str(arg) == name: |
|
|
|
if str(arg) == name: |
|
|
|
old_str_of_interest = in_file_str[modifier.source_mapping['start']: |
|
|
|
old_str_of_interest = in_file_str[modifier.source_mapping['start']: |
|
|
|
modifier.source_mapping['start'] + |
|
|
|
modifier.source_mapping['start'] + |
|
|
|
modifier.source_mapping['length']] |
|
|
|
modifier.source_mapping['length']] |
|
|
|
old_str_of_interest_beyond_modifier_name = old_str_of_interest.decode('utf-8')\ |
|
|
|
old_str_of_interest_beyond_modifier_name = old_str_of_interest.decode('utf-8')\ |
|
|
|
.split('(')[1] |
|
|
|
.split('(')[1] |
|
|
|
if(name[0] == '_'): |
|
|
|
if(name[0] == '_'): |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+name+r'(.*)', r'\1'+name[0]+ |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+name+r'(.*)', r'\1'+name[0]+ |
|
|
|
name[1].upper()+name[2:]+r'\2', |
|
|
|
name[1].upper()+name[2:]+r'\2', |
|
|
|
old_str_of_interest_beyond_modifier_name, 1) |
|
|
|
old_str_of_interest_beyond_modifier_name, 1) |
|
|
|
else: |
|
|
|
else: |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+name+r'(.*)', r'\1'+'_'+ |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+name+r'(.*)', r'\1'+'_'+ |
|
|
|
name[0].upper()+name[1:]+r'\2', |
|
|
|
name[0].upper()+name[1:]+r'\2', |
|
|
|
old_str_of_interest_beyond_modifier_name, 1) |
|
|
|
old_str_of_interest_beyond_modifier_name, 1) |
|
|
|
if num_repl != 0: |
|
|
|
if num_repl != 0: |
|
|
|
patch = { |
|
|
|
patch = { |
|
|
|
"file" : in_file, |
|
|
|
"file" : in_file, |
|
|
|
"detector" : "naming-convention (parameter uses)", |
|
|
|
"detector" : "naming-convention (parameter uses)", |
|
|
|
"start" : modifier.source_mapping['start'] + |
|
|
|
"start" : modifier.source_mapping['start'] + |
|
|
|
len(old_str_of_interest.decode('utf-8').split('(')[0]) + 1, |
|
|
|
len(old_str_of_interest.decode('utf-8').split('(')[0]) + 1, |
|
|
|
"end" : modifier.source_mapping['start'] + modifier.source_mapping['length'], |
|
|
|
"end" : modifier.source_mapping['start'] + modifier.source_mapping['length'], |
|
|
|
"old_string" : old_str_of_interest_beyond_modifier_name, |
|
|
|
"old_string" : old_str_of_interest_beyond_modifier_name, |
|
|
|
"new_string" : new_str_of_interest |
|
|
|
"new_string" : new_str_of_interest |
|
|
|
} |
|
|
|
} |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
else: |
|
|
|
else: |
|
|
|
raise SlitherException("Could not find parameter use in modifier?!") |
|
|
|
raise SlitherException("Could not find parameter use in modifier?!") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _create_patch_state_variable_declaration(format_info): |
|
|
|
def _create_patch_state_variable_declaration(format_info): |
|
|
@ -535,28 +542,33 @@ def _create_patch_state_variable_declaration(format_info): |
|
|
|
modify_loc_start, modify_loc_end = format_info.loc_start, format_info.loc_end |
|
|
|
modify_loc_start, modify_loc_end = format_info.loc_start, format_info.loc_end |
|
|
|
_target = format_info.target |
|
|
|
_target = format_info.target |
|
|
|
|
|
|
|
|
|
|
|
for contract in slither.contracts: |
|
|
|
target_contract = slither.get_contract_from_name(contract_name) |
|
|
|
if (contract.name == contract_name): |
|
|
|
if not target_contract: |
|
|
|
for var in contract.state_variables: |
|
|
|
raise SlitherException(f"Contract not found {contract_name}") |
|
|
|
if (var.name == name): |
|
|
|
target_var = target_contract.get_state_variable_from_name(name) |
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
if not target_var: |
|
|
|
old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end] |
|
|
|
raise SlitherException(f"Contract not found {name}") |
|
|
|
m = re.search(name, old_str_of_interest.decode('utf-8')) |
|
|
|
|
|
|
|
if (_target == "variable_constant"): |
|
|
|
# TODO (JF) target_var is not used, the above checks could be removed? |
|
|
|
new_string = old_str_of_interest.decode('utf-8')[m.span()[0]:m.span()[1]].upper() |
|
|
|
|
|
|
|
else: |
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
new_string = old_str_of_interest.decode('utf-8')[m.span()[0]:m.span()[1]] |
|
|
|
old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end] |
|
|
|
new_string = new_string[0].lower()+new_string[1:] |
|
|
|
m = re.search(name, old_str_of_interest.decode('utf-8')) |
|
|
|
patch = { |
|
|
|
if (_target == "variable_constant"): |
|
|
|
"file" : in_file, |
|
|
|
new_string = old_str_of_interest.decode('utf-8')[m.span()[0]:m.span()[1]].upper() |
|
|
|
"detector" : "naming-convention (state variable declaration)", |
|
|
|
else: |
|
|
|
"start" : modify_loc_start+m.span()[0], |
|
|
|
new_string = old_str_of_interest.decode('utf-8')[m.span()[0]:m.span()[1]] |
|
|
|
"end" : modify_loc_start+m.span()[1], |
|
|
|
new_string = new_string[0].lower()+new_string[1:] |
|
|
|
"old_string" : old_str_of_interest.decode('utf-8')[m.span()[0]:m.span()[1]], |
|
|
|
patch = { |
|
|
|
"new_string" : new_string |
|
|
|
"file" : in_file, |
|
|
|
} |
|
|
|
"detector" : "naming-convention (state variable declaration)", |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
"start" : modify_loc_start+m.span()[0], |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
"end" : modify_loc_start+m.span()[1], |
|
|
|
|
|
|
|
"old_string" : old_str_of_interest.decode('utf-8')[m.span()[0]:m.span()[1]], |
|
|
|
|
|
|
|
"new_string" : new_string |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
|
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _create_patch_state_variable_uses(format_info): |
|
|
|
def _create_patch_state_variable_uses(format_info): |
|
|
@ -566,60 +578,32 @@ def _create_patch_state_variable_uses(format_info): |
|
|
|
_target = format_info.target |
|
|
|
_target = format_info.target |
|
|
|
|
|
|
|
|
|
|
|
# To-do: Check cross-contract state variable uses |
|
|
|
# To-do: Check cross-contract state variable uses |
|
|
|
for contract in slither.contracts: |
|
|
|
target_contract = slither.get_contract_from_name(contract_name) |
|
|
|
if (contract.name == contract_name): |
|
|
|
if not target_contract: |
|
|
|
target_contract = contract |
|
|
|
raise SlitherException(f"Contract not found {contract_name}") |
|
|
|
for contract in slither.contracts: |
|
|
|
|
|
|
|
if (contract == target_contract or (contract in target_contract.derived_contracts)): |
|
|
|
|
|
|
|
fms = contract.functions + contract.modifiers |
|
|
|
|
|
|
|
for fm in fms: |
|
|
|
|
|
|
|
for node in fm.nodes: |
|
|
|
|
|
|
|
vars = node._expression_vars_written + node._expression_vars_read |
|
|
|
|
|
|
|
for v in vars: |
|
|
|
|
|
|
|
if isinstance(v, Identifier) and str(v) == name and [str(sv) for sv in |
|
|
|
|
|
|
|
(node._state_vars_read + |
|
|
|
|
|
|
|
node._state_vars_written) |
|
|
|
|
|
|
|
if str(sv) == name]: |
|
|
|
|
|
|
|
modify_loc_start = int(v.source_mapping['start']) |
|
|
|
|
|
|
|
modify_loc_end = int(v.source_mapping['start']) + int(v.source_mapping['length']) |
|
|
|
|
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
|
|
|
|
old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end] |
|
|
|
|
|
|
|
if (_target == "variable_constant"): |
|
|
|
|
|
|
|
new_str_of_interest = old_str_of_interest.decode('utf-8').upper() |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
new_str_of_interest = old_str_of_interest.decode('utf-8') |
|
|
|
|
|
|
|
new_str_of_interest = new_str_of_interest[0].lower()+new_str_of_interest[1:] |
|
|
|
|
|
|
|
patch = { |
|
|
|
|
|
|
|
"file" : in_file, |
|
|
|
|
|
|
|
"detector" : "naming-convention (state variable uses)", |
|
|
|
|
|
|
|
"start" : modify_loc_start, |
|
|
|
|
|
|
|
"end" : modify_loc_end, |
|
|
|
|
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
|
|
|
|
"new_string" : new_str_of_interest |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
|
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _create_patch_enum_definition(format_info): |
|
|
|
|
|
|
|
slither, patches, name = format_info.slither, format_info.patches, format_info.name |
|
|
|
|
|
|
|
in_file, in_file_relative = format_info.in_file, format_info.in_file_relative |
|
|
|
|
|
|
|
contract_name = format_info.contract_name |
|
|
|
|
|
|
|
modify_loc_start, modify_loc_end = format_info.loc_start, format_info.loc_end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for contract in slither.contracts: |
|
|
|
for contract in [target_contract] + target_contract.derived_contracts: |
|
|
|
if (contract.name == contract_name): |
|
|
|
fms = contract.functions + contract.modifiers |
|
|
|
for enum in contract.enums: |
|
|
|
for fm in fms: |
|
|
|
if (enum.name == name): |
|
|
|
for node in fm.nodes: |
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
vars = node._expression_vars_written + node._expression_vars_read |
|
|
|
old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end] |
|
|
|
for v in vars: |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+"enum"+r'(.*)'+name, r'\1'+"enum"+r'\2'+ |
|
|
|
if isinstance(v, Identifier) and str(v) == name and [str(sv) for sv in |
|
|
|
name[0].capitalize()+name[1:], |
|
|
|
(node._state_vars_read + |
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
node._state_vars_written) |
|
|
|
if num_repl != 0: |
|
|
|
if str(sv) == name]: |
|
|
|
|
|
|
|
modify_loc_start = int(v.source_mapping['start']) |
|
|
|
|
|
|
|
modify_loc_end = int(v.source_mapping['start']) + int(v.source_mapping['length']) |
|
|
|
|
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
|
|
|
|
old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end] |
|
|
|
|
|
|
|
if (_target == "variable_constant"): |
|
|
|
|
|
|
|
new_str_of_interest = old_str_of_interest.decode('utf-8').upper() |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
new_str_of_interest = old_str_of_interest.decode('utf-8') |
|
|
|
|
|
|
|
new_str_of_interest = new_str_of_interest[0].lower()+new_str_of_interest[1:] |
|
|
|
patch = { |
|
|
|
patch = { |
|
|
|
"file" : in_file, |
|
|
|
"file" : in_file, |
|
|
|
"detector" : "naming-convention (enum definition)", |
|
|
|
"detector" : "naming-convention (state variable uses)", |
|
|
|
"start" : modify_loc_start, |
|
|
|
"start" : modify_loc_start, |
|
|
|
"end" : modify_loc_end, |
|
|
|
"end" : modify_loc_end, |
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
@ -627,8 +611,42 @@ def _create_patch_enum_definition(format_info): |
|
|
|
} |
|
|
|
} |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
else: |
|
|
|
|
|
|
|
raise SlitherException("Could not find enum?!") |
|
|
|
|
|
|
|
|
|
|
|
def _create_patch_enum_definition(format_info): |
|
|
|
|
|
|
|
slither, patches, name = format_info.slither, format_info.patches, format_info.name |
|
|
|
|
|
|
|
in_file, in_file_relative = format_info.in_file, format_info.in_file_relative |
|
|
|
|
|
|
|
contract_name = format_info.contract_name |
|
|
|
|
|
|
|
modify_loc_start, modify_loc_end = format_info.loc_start, format_info.loc_end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
target_contract = slither.get_contract_from_name(contract_name) |
|
|
|
|
|
|
|
if not target_contract: |
|
|
|
|
|
|
|
raise SlitherException(f"Contract not found {contract_name}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
target_enum = slither.get_enum_from_name(name) |
|
|
|
|
|
|
|
if not target_enum: |
|
|
|
|
|
|
|
raise SlitherException(f"Enum not found {name}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# TODO (JF) target_enum is not used, the above checks could be removed? |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
|
|
|
|
old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end] |
|
|
|
|
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+"enum"+r'(.*)'+name, r'\1'+"enum"+r'\2'+ |
|
|
|
|
|
|
|
name[0].capitalize()+name[1:], |
|
|
|
|
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
|
|
|
|
if num_repl != 0: |
|
|
|
|
|
|
|
patch = { |
|
|
|
|
|
|
|
"file" : in_file, |
|
|
|
|
|
|
|
"detector" : "naming-convention (enum definition)", |
|
|
|
|
|
|
|
"start" : modify_loc_start, |
|
|
|
|
|
|
|
"end" : modify_loc_end, |
|
|
|
|
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
|
|
|
|
"new_string" : new_str_of_interest |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
|
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
raise SlitherException("Could not find enum?!") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _create_patch_enum_uses(format_info): |
|
|
|
def _create_patch_enum_uses(format_info): |
|
|
@ -636,87 +654,87 @@ def _create_patch_enum_uses(format_info): |
|
|
|
in_file, in_file_relative = format_info.in_file, format_info.in_file_relative |
|
|
|
in_file, in_file_relative = format_info.in_file, format_info.in_file_relative |
|
|
|
contract_name = format_info.contract_name |
|
|
|
contract_name = format_info.contract_name |
|
|
|
|
|
|
|
|
|
|
|
for contract in slither.contracts: |
|
|
|
target_contract = slither.get_contract_from_name(contract_name) |
|
|
|
if (contract.name == contract_name): |
|
|
|
if not target_contract: |
|
|
|
target_contract = contract |
|
|
|
raise SlitherException(f"Contract not found {contract_name}") |
|
|
|
for contract in slither.contracts: |
|
|
|
|
|
|
|
if (contract == target_contract or (contract in target_contract.derived_contracts)): |
|
|
|
for contract in [target_contract] + target_contract.derived_contracts: |
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
# Check state variable declarations of enum type |
|
|
|
# Check state variable declarations of enum type |
|
|
|
# To-do: Deep-check aggregate types (struct and mapping) |
|
|
|
# To-do: Deep-check aggregate types (struct and mapping) |
|
|
|
svs = contract.variables |
|
|
|
svs = contract.variables |
|
|
|
for sv in svs: |
|
|
|
for sv in svs: |
|
|
|
if (str(sv.type) == contract_name + "." + name): |
|
|
|
if (str(sv.type) == contract_name + "." + name): |
|
|
|
old_str_of_interest = in_file_str[sv.source_mapping['start']:(sv.source_mapping['start']+ |
|
|
|
old_str_of_interest = in_file_str[sv.source_mapping['start']:(sv.source_mapping['start']+ |
|
|
|
sv.source_mapping['length'])] |
|
|
|
sv.source_mapping['length'])] |
|
|
|
|
|
|
|
(new_str_of_interest, num_repl) = re.subn(name, name.capitalize(), |
|
|
|
|
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
|
|
|
|
patch = { |
|
|
|
|
|
|
|
"file" : in_file, |
|
|
|
|
|
|
|
"detector" : "naming-convention (enum use)", |
|
|
|
|
|
|
|
"start" : sv.source_mapping['start'], |
|
|
|
|
|
|
|
"end" : sv.source_mapping['start'] + sv.source_mapping['length'], |
|
|
|
|
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
|
|
|
|
"new_string" : new_str_of_interest |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
|
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
|
|
|
|
# Check function+modifier locals+parameters+returns |
|
|
|
|
|
|
|
# To-do: Deep-check aggregate types (struct and mapping) |
|
|
|
|
|
|
|
fms = contract.functions + contract.modifiers |
|
|
|
|
|
|
|
for fm in fms: |
|
|
|
|
|
|
|
# Enum declarations |
|
|
|
|
|
|
|
for v in fm.variables: |
|
|
|
|
|
|
|
if (str(v.type) == contract_name + "." + name): |
|
|
|
|
|
|
|
old_str_of_interest = in_file_str[v.source_mapping['start']:(v.source_mapping['start']+ |
|
|
|
|
|
|
|
v.source_mapping['length'])] |
|
|
|
(new_str_of_interest, num_repl) = re.subn(name, name.capitalize(), |
|
|
|
(new_str_of_interest, num_repl) = re.subn(name, name.capitalize(), |
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
patch = { |
|
|
|
patch = { |
|
|
|
"file" : in_file, |
|
|
|
"file" : in_file, |
|
|
|
"detector" : "naming-convention (enum use)", |
|
|
|
"detector" : "naming-convention (enum use)", |
|
|
|
"start" : sv.source_mapping['start'], |
|
|
|
"start" : v.source_mapping['start'], |
|
|
|
"end" : sv.source_mapping['start'] + sv.source_mapping['length'], |
|
|
|
"end" : v.source_mapping['start'] + v.source_mapping['length'], |
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
"new_string" : new_str_of_interest |
|
|
|
"new_string" : new_str_of_interest |
|
|
|
} |
|
|
|
} |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
# Check function+modifier locals+parameters+returns |
|
|
|
# Capture enum uses such as "num = numbers.ONE;" |
|
|
|
# To-do: Deep-check aggregate types (struct and mapping) |
|
|
|
for function in contract.functions: |
|
|
|
fms = contract.functions + contract.modifiers |
|
|
|
for node in function.nodes: |
|
|
|
for fm in fms: |
|
|
|
for ir in node.irs: |
|
|
|
# Enum declarations |
|
|
|
if isinstance(ir, Member): |
|
|
|
for v in fm.variables: |
|
|
|
if str(ir.variable_left) == name: |
|
|
|
if (str(v.type) == contract_name + "." + name): |
|
|
|
old_str_of_interest = in_file_str[node.source_mapping['start']: |
|
|
|
old_str_of_interest = in_file_str[v.source_mapping['start']:(v.source_mapping['start']+ |
|
|
|
(node.source_mapping['start']+ |
|
|
|
v.source_mapping['length'])] |
|
|
|
node.source_mapping['length'])].decode('utf-8')\ |
|
|
|
(new_str_of_interest, num_repl) = re.subn(name, name.capitalize(), |
|
|
|
.split('=')[1] |
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
m = re.search(r'(.*)'+name, old_str_of_interest) |
|
|
|
patch = { |
|
|
|
old_str_of_interest = old_str_of_interest[m.span()[0]:] |
|
|
|
"file" : in_file, |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+name, r'\1'+name[0].upper()+name[1:], |
|
|
|
"detector" : "naming-convention (enum use)", |
|
|
|
old_str_of_interest, 1) |
|
|
|
"start" : v.source_mapping['start'], |
|
|
|
if num_repl != 0: |
|
|
|
"end" : v.source_mapping['start'] + v.source_mapping['length'], |
|
|
|
patch = { |
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
"file" : in_file, |
|
|
|
"new_string" : new_str_of_interest |
|
|
|
"detector" : "naming-convention (enum use)", |
|
|
|
} |
|
|
|
"start" : node.source_mapping['start'] + |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
len(in_file_str[node.source_mapping['start']: |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
(node.source_mapping['start']+ |
|
|
|
# Capture enum uses such as "num = numbers.ONE;" |
|
|
|
node.source_mapping['length'])].decode('utf-8').split('=')[0]) + |
|
|
|
for function in contract.functions: |
|
|
|
1 + m.span()[0], |
|
|
|
for node in function.nodes: |
|
|
|
"end" : node.source_mapping['start'] + |
|
|
|
for ir in node.irs: |
|
|
|
len(in_file_str[node.source_mapping['start']:(node.source_mapping['start']+ |
|
|
|
if isinstance(ir, Member): |
|
|
|
node.source_mapping['length'])].\ |
|
|
|
if str(ir.variable_left) == name: |
|
|
|
decode('utf-8').split('=')[0]) + 1 + m.span()[0] + len(old_str_of_interest), |
|
|
|
old_str_of_interest = in_file_str[node.source_mapping['start']: |
|
|
|
"old_string" : old_str_of_interest, |
|
|
|
(node.source_mapping['start']+ |
|
|
|
"new_string" : new_str_of_interest |
|
|
|
node.source_mapping['length'])].decode('utf-8')\ |
|
|
|
} |
|
|
|
.split('=')[1] |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
m = re.search(r'(.*)'+name, old_str_of_interest) |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
old_str_of_interest = old_str_of_interest[m.span()[0]:] |
|
|
|
else: |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+name, r'\1'+name[0].upper()+name[1:], |
|
|
|
raise SlitherException("Could not find new object?!") |
|
|
|
old_str_of_interest, 1) |
|
|
|
# To-do: Check any other place/way where enum type is used |
|
|
|
if num_repl != 0: |
|
|
|
|
|
|
|
patch = { |
|
|
|
|
|
|
|
"file" : in_file, |
|
|
|
|
|
|
|
"detector" : "naming-convention (enum use)", |
|
|
|
|
|
|
|
"start" : node.source_mapping['start'] + |
|
|
|
|
|
|
|
len(in_file_str[node.source_mapping['start']: |
|
|
|
|
|
|
|
(node.source_mapping['start']+ |
|
|
|
|
|
|
|
node.source_mapping['length'])].decode('utf-8').split('=')[0]) + |
|
|
|
|
|
|
|
1 + m.span()[0], |
|
|
|
|
|
|
|
"end" : node.source_mapping['start'] + |
|
|
|
|
|
|
|
len(in_file_str[node.source_mapping['start']:(node.source_mapping['start']+ |
|
|
|
|
|
|
|
node.source_mapping['length'])].\ |
|
|
|
|
|
|
|
decode('utf-8').split('=')[0]) + 1 + m.span()[0] + len(old_str_of_interest), |
|
|
|
|
|
|
|
"old_string" : old_str_of_interest, |
|
|
|
|
|
|
|
"new_string" : new_str_of_interest |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
|
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
raise SlitherException("Could not find new object?!") |
|
|
|
|
|
|
|
# To-do: Check any other place/way where enum type is used |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _create_patch_struct_definition(format_info): |
|
|
|
def _create_patch_struct_definition(format_info): |
|
|
@ -725,28 +743,34 @@ def _create_patch_struct_definition(format_info): |
|
|
|
contract_name = format_info.contract_name |
|
|
|
contract_name = format_info.contract_name |
|
|
|
modify_loc_start, modify_loc_end = format_info.loc_start, format_info.loc_end |
|
|
|
modify_loc_start, modify_loc_end = format_info.loc_start, format_info.loc_end |
|
|
|
|
|
|
|
|
|
|
|
for contract in slither.contracts: |
|
|
|
target_contract = slither.get_contract_from_name(contract_name) |
|
|
|
if (contract.name == contract_name): |
|
|
|
if not target_contract: |
|
|
|
for struct in contract.structures: |
|
|
|
raise SlitherException(f"Contract not found {contract_name}") |
|
|
|
if (struct.name == name): |
|
|
|
|
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
target_structure = slither.get_structure_from_name(name) |
|
|
|
old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end] |
|
|
|
if not target_structure: |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+"struct"+r'(.*)'+name, r'\1'+"struct"+r'\2'+ |
|
|
|
raise SlitherException(f"Structure not found {name}") |
|
|
|
name[0].capitalize()+name[1:], |
|
|
|
|
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
# TODO (JF) target_structure is not used, the above checks could be removed? |
|
|
|
if num_repl != 0: |
|
|
|
|
|
|
|
patch = { |
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
"file" : in_file, |
|
|
|
old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end] |
|
|
|
"detector" : "naming-convention (struct definition)", |
|
|
|
(new_str_of_interest, num_repl) = re.subn(r'(.*)'+"struct"+r'(.*)'+name, r'\1'+"struct"+r'\2'+ |
|
|
|
"start" : modify_loc_start, |
|
|
|
name[0].capitalize()+name[1:], |
|
|
|
"end" : modify_loc_end, |
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
if num_repl != 0: |
|
|
|
"new_string" : new_str_of_interest |
|
|
|
patch = { |
|
|
|
} |
|
|
|
"file" : in_file, |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
"detector" : "naming-convention (struct definition)", |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
"start" : modify_loc_start, |
|
|
|
else: |
|
|
|
"end" : modify_loc_end, |
|
|
|
raise SlitherException("Could not find struct?!") |
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
|
|
|
|
"new_string" : new_str_of_interest |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
|
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
raise SlitherException("Could not find struct?!") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _create_patch_struct_uses(format_info): |
|
|
|
def _create_patch_struct_uses(format_info): |
|
|
@ -754,49 +778,49 @@ def _create_patch_struct_uses(format_info): |
|
|
|
in_file, in_file_relative = format_info.in_file, format_info.in_file_relative |
|
|
|
in_file, in_file_relative = format_info.in_file, format_info.in_file_relative |
|
|
|
contract_name = format_info.contract_name |
|
|
|
contract_name = format_info.contract_name |
|
|
|
|
|
|
|
|
|
|
|
for contract in slither.contracts: |
|
|
|
target_contract = slither.get_contract_from_name(contract_name) |
|
|
|
if (contract.name == contract_name): |
|
|
|
if not target_contract: |
|
|
|
target_contract = contract |
|
|
|
raise SlitherException(f"Contract not found {contract_name}") |
|
|
|
for contract in slither.contracts: |
|
|
|
|
|
|
|
if (contract == target_contract or (contract in target_contract.derived_contracts)): |
|
|
|
for contract in [target_contract] + target_contract.derived_contracts: |
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
in_file_str = slither.source_code[in_file].encode('utf-8') |
|
|
|
# Check state variables of struct type |
|
|
|
# Check state variables of struct type |
|
|
|
# To-do: Deep-check aggregate types (struct and mapping) |
|
|
|
# To-do: Deep-check aggregate types (struct and mapping) |
|
|
|
svs = contract.variables |
|
|
|
svs = contract.variables |
|
|
|
for sv in svs: |
|
|
|
for sv in svs: |
|
|
|
if (str(sv.type) == contract_name + "." + name): |
|
|
|
if (str(sv.type) == contract_name + "." + name): |
|
|
|
old_str_of_interest = in_file_str[sv.source_mapping['start']:(sv.source_mapping['start']+ |
|
|
|
old_str_of_interest = in_file_str[sv.source_mapping['start']:(sv.source_mapping['start']+ |
|
|
|
sv.source_mapping['length'])] |
|
|
|
sv.source_mapping['length'])] |
|
|
|
|
|
|
|
(new_str_of_interest, num_repl) = re.subn(name, name.capitalize(), |
|
|
|
|
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
|
|
|
|
patch = { |
|
|
|
|
|
|
|
"file" : in_file, |
|
|
|
|
|
|
|
"detector" : "naming-convention (struct use)", |
|
|
|
|
|
|
|
"start" : sv.source_mapping['start'], |
|
|
|
|
|
|
|
"end" : sv.source_mapping['start'] + sv.source_mapping['length'], |
|
|
|
|
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
|
|
|
|
"new_string" : new_str_of_interest |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
|
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
|
|
|
|
# Check function+modifier locals+parameters+returns |
|
|
|
|
|
|
|
# To-do: Deep-check aggregate types (struct and mapping) |
|
|
|
|
|
|
|
fms = contract.functions + contract.modifiers |
|
|
|
|
|
|
|
for fm in fms: |
|
|
|
|
|
|
|
for v in fm.variables: |
|
|
|
|
|
|
|
if (str(v.type) == contract_name + "." + name): |
|
|
|
|
|
|
|
old_str_of_interest = in_file_str[v.source_mapping['start']:(v.source_mapping['start']+ |
|
|
|
|
|
|
|
v.source_mapping['length'])] |
|
|
|
(new_str_of_interest, num_repl) = re.subn(name, name.capitalize(), |
|
|
|
(new_str_of_interest, num_repl) = re.subn(name, name.capitalize(), |
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
patch = { |
|
|
|
patch = { |
|
|
|
"file" : in_file, |
|
|
|
"file" : in_file, |
|
|
|
"detector" : "naming-convention (struct use)", |
|
|
|
"detector" : "naming-convention (struct use)", |
|
|
|
"start" : sv.source_mapping['start'], |
|
|
|
"start" : v.source_mapping['start'], |
|
|
|
"end" : sv.source_mapping['start'] + sv.source_mapping['length'], |
|
|
|
"end" : v.source_mapping['start'] + v.source_mapping['length'], |
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
"new_string" : new_str_of_interest |
|
|
|
"new_string" : new_str_of_interest |
|
|
|
} |
|
|
|
} |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
# Check function+modifier locals+parameters+returns |
|
|
|
# To-do: Check any other place/way where struct type is used (e.g. typecast) |
|
|
|
# To-do: Deep-check aggregate types (struct and mapping) |
|
|
|
|
|
|
|
fms = contract.functions + contract.modifiers |
|
|
|
|
|
|
|
for fm in fms: |
|
|
|
|
|
|
|
for v in fm.variables: |
|
|
|
|
|
|
|
if (str(v.type) == contract_name + "." + name): |
|
|
|
|
|
|
|
old_str_of_interest = in_file_str[v.source_mapping['start']:(v.source_mapping['start']+ |
|
|
|
|
|
|
|
v.source_mapping['length'])] |
|
|
|
|
|
|
|
(new_str_of_interest, num_repl) = re.subn(name, name.capitalize(), |
|
|
|
|
|
|
|
old_str_of_interest.decode('utf-8'), 1) |
|
|
|
|
|
|
|
patch = { |
|
|
|
|
|
|
|
"file" : in_file, |
|
|
|
|
|
|
|
"detector" : "naming-convention (struct use)", |
|
|
|
|
|
|
|
"start" : v.source_mapping['start'], |
|
|
|
|
|
|
|
"end" : v.source_mapping['start'] + v.source_mapping['length'], |
|
|
|
|
|
|
|
"old_string" : old_str_of_interest.decode('utf-8'), |
|
|
|
|
|
|
|
"new_string" : new_str_of_interest |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if not patch in patches[in_file_relative]: |
|
|
|
|
|
|
|
patches[in_file_relative].append(patch) |
|
|
|
|
|
|
|
# To-do: Check any other place/way where struct type is used (e.g. typecast) |
|
|
|
|
|
|
|