import sys, re from collections import defaultdict from slither.detectors.variables.unused_state_variables import UnusedStateVars from slither.detectors.attributes.incorrect_solc import IncorrectSolc from slither.detectors.attributes.constant_pragma import ConstantPragma from slither.detectors.naming_convention.naming_convention import NamingConvention from slither.detectors.functions.external_function import ExternalFunction from slither.detectors.variables.possible_const_state_variables import ConstCandidateStateVars from slither.detectors.attributes.const_functions import ConstantFunctions from slither.slithir.operations import InternalCall from slither.core.expressions.call_expression import CallExpression from slither.core.expressions.expression import Expression from slither.core.expressions.identifier import Identifier from slither_format.format_unused_state import FormatUnusedState from slither_format.format_solc_version import FormatSolcVersion from slither_format.format_pragma import FormatPragma from slither_format.format_naming_convention import FormatNamingConvention from slither_format.format_external_function import FormatExternalFunction from slither_format.format_constable_states import FormatConstableStates from slither_format.format_constant_function import FormatConstantFunction all_detectors = { 'unused-state': UnusedStateVars, 'solc-version': IncorrectSolc, 'pragma': ConstantPragma, 'naming-convention': NamingConvention, 'external-function': ExternalFunction, 'constable-states' : ConstCandidateStateVars, 'constant-function': ConstantFunctions } def slither_format(args, slither): patches = defaultdict(list) detectors_to_run = choose_detectors(args) for detector in detectors_to_run: slither.register_detector(detector) results = [] detector_results = slither.run_detectors() detector_results = [x for x in detector_results if x] # remove empty results detector_results = [item for sublist in detector_results for item in sublist] # flatten results.extend(detector_results) number_of_slither_results = get_number_of_slither_results(detector_results) apply_detector_results(slither, patches, detector_results) sort_patches(patches) if args.verbose: print("Number of Slither results: " + str(number_of_slither_results)) print_patches(patches) apply_patches(slither, patches) def sort_patches(patches): for file in patches: n = len(patches[file]) for i in range(n): for j in range (0,n-i-1): if int(patches[file][j]['start']) >= int(patches[file][j+1]['end']): temp = patches[file][j+1] patches[file][j+1] = patches[file][j] patches[file][j] = temp def apply_patches(slither, patches): for file in patches: _in_file = file in_file_str = slither.source_code[_in_file] out_file_str = "" for i in range(len(patches[file])): if i != 0: out_file_str += in_file_str[int(patches[file][i-1]['end']):int(patches[file][i]['start'])] else: out_file_str += in_file_str[:int(patches[file][i]['start'])] out_file_str += patches[file][i]['new_string'] out_file_str += in_file_str[int(patches[file][i]['end']):] out_file = open(_in_file+".format",'w') out_file.write(out_file_str) out_file.close() def print_patches(patches): number_of_patches = 0 for file in patches: number_of_patches += len(patches[file]) print("Number of patches: " + str(number_of_patches)) for file in patches: print("Patch file: " + file) for patch in patches[file]: print("Detector: " + patch['detector']) print("Old string: " + patch['old_string'].replace("\n","")) print("New string: " + patch['new_string'].replace("\n","")) print("Location start: " + str(patch['start'])) print("Location end: " + str(patch['end'])) def choose_detectors(args): # If detectors are specified, run only these ones detectors_to_run = [] if args.detectors_to_run == 'all': for d in all_detectors: detectors_to_run.append(all_detectors[d]) else: for d in args.detectors_to_run.split(','): if d in all_detectors: detectors_to_run.append(all_detectors[d]) else: raise Exception('Error: {} is not a detector'.format(d)) return detectors_to_run def apply_detector_results(slither, patches, detector_results): for result in detector_results: if result['check'] == 'unused-state': FormatUnusedState.format(slither, patches, result['elements']) elif result['check'] == 'solc-version': FormatSolcVersion.format(slither, patches, result['elements']) elif result['check'] == 'pragma': FormatPragma.format(slither, patches, result['elements']) elif result['check'] == 'naming-convention': FormatNamingConvention.format(slither, patches, result['elements']) elif result['check'] == 'external-function': FormatExternalFunction.format(slither, patches, result['elements']) elif result['check'] == 'constable-states': FormatConstableStates.format(slither, patches, result['elements']) elif result['check'] == 'constant-function': FormatConstantFunction.format(slither, patches, result['elements']) else: print("Not Supported Yet.") sys.exit(-1) def get_number_of_slither_results (detector_results): number_of_slither_results = 0 for result in detector_results: for elem in result['elements']: if (result['check'] == 'constant-function' and elem['type'] != "function"): continue if (result['check'] == 'unused-state' and elem['type'] != "variable"): continue number_of_slither_results += 1 return number_of_slither_results