Merge branch 'dev-slither-format-tool-only-new' of github.com:crytic/slither into dev-slither-format-tool-only-new

pull/238/head
Josselin 5 years ago
commit 055375d205
  1. 17
      utils/slither_format/README.md
  2. 5
      utils/slither_format/__main__.py
  3. 8
      utils/slither_format/slither_format.py
  4. 24
      utils/slither_format/tests/runSlitherFormat.py

@ -28,20 +28,23 @@ Slither detectors highlight names, context and source-mapping of code constructs
## Usage ## Usage
Run Slither-format on a single file: Run Slither-format on a single file:
```
```
$ slither-format ./utils/slither_format/tests/test_data/constant.sol $ slither-format ./utils/slither_format/tests/test_data/constant.sol
``` ```
This produces `constant.sol.format` file which has all the feature replacements. This produces a `constant.sol.format` file which has all the feature replacements. It also produces a `constant.sol.format.patch` file which is a `git` compatible patch file that can be used to apply format diffs to the original file.
## Dependencies ## Dependencies
Slither-format requires Slither and all its dependencies Slither-format requires Slither and all its dependencies
## Known Limitations ## To-do List of Known Limitations
* Naming convention formatting on parameter uses does not work for NatSpec @param attributes 1. Naming convention formatting on parameter uses does not work for NatSpec @param attributes.
* Naming convention formatting on parameter uses does not work for variables used as indices on LHS (e.g. `_to` in `balances[_to] = 100`) 2. Naming convention formatting on parameter uses does not work for variables used as indices on LHS (e.g. `_to` in `balances[_to] = 100`).
3. Overlapping patches are ignored now - Apply the more important patch based on heuristics or user input.
4. Other to-do's as commented in the code.
## Developer Testing ## Developer Testing
@ -52,6 +55,8 @@ $ python3 ./slither_format/tests/test_constable_states.py
$ python3 ./slither_format/tests/test_constant_function.py $ python3 ./slither_format/tests/test_constant_function.py
$ python3 ./slither_format/tests/test_solc_version.py $ python3 ./slither_format/tests/test_solc_version.py
$ python3 ./slither_format/tests/test_pragma.py $ python3 ./slither_format/tests/test_pragma.py
$ python3 ./slither_format/tests/test_naming_convention.py $ python3 ./slither_format/tests/test_naming_convention.py (Has one expected failure because of limitation #2.)
$ python3 ./slither_format/tests/test_detector_combinations.py
$ python3 ./slither_format/tests/run_all_tests.py $ python3 ./slither_format/tests/run_all_tests.py
$ python3 ./slither_format/tests/runSlitherFormat.py
``` ```

@ -9,6 +9,7 @@ from crytic_compile import cryticparser
logging.basicConfig() logging.basicConfig()
logging.getLogger("Slither").setLevel(logging.INFO) logging.getLogger("Slither").setLevel(logging.INFO)
# Slither detectors for which slither-format currently works
available_detectors = ["unused-state", available_detectors = ["unused-state",
"solc-version", "solc-version",
"pragma", "pragma",
@ -30,6 +31,10 @@ def parse_args():
parser.add_argument('filename', help='The filename of the contract or truffle directory to analyze.') parser.add_argument('filename', help='The filename of the contract or truffle directory to analyze.')
parser.add_argument('--verbose-test', '-v', help='verbose mode output for testing',action='store_true',default=False) parser.add_argument('--verbose-test', '-v', help='verbose mode output for testing',action='store_true',default=False)
parser.add_argument('--verbose-json', '-j', help='verbose json output',action='store_true',default=False) parser.add_argument('--verbose-json', '-j', help='verbose json output',action='store_true',default=False)
parser.add_argument('--version',
help='displays the current version',
version='0.1.0',
action='version')
group_detector = parser.add_argument_group('Detectors') group_detector = parser.add_argument_group('Detectors')
group_detector.add_argument('--detect', group_detector.add_argument('--detect',

@ -111,12 +111,15 @@ def generate_patch_files(slither, patches):
out_file = open(_in_file+".format",'w') out_file = open(_in_file+".format",'w')
out_file.write(out_file_str) out_file.write(out_file_str)
out_file.close() out_file.close()
logger.info("slither-format successful.")
logger.info("Created formatted file: " + _in_file+".format")
patch_file_name = _in_file + ".format.patch" patch_file_name = _in_file + ".format.patch"
outFD = open(patch_file_name,"w") outFD = open(patch_file_name,"w")
logger.info(f'Output new file in {patch_file_name}') logger.info(f'Output new file in {patch_file_name}')
p1 = subprocess.Popen(['diff', '-u', _in_file, _in_file+".format"], stdout=outFD) p1 = subprocess.Popen(['diff', '-u', _in_file, _in_file+".format"], stdout=outFD)
p1.wait() p1.wait()
outFD.close() outFD.close()
logger.info("Created patch file: " + patch_file_name)
def print_patches(number_of_slither_results, patches): def print_patches(number_of_slither_results, patches):
logger.info("Number of Slither results: " + str(number_of_slither_results)) logger.info("Number of Slither results: " + str(number_of_slither_results))
@ -178,6 +181,9 @@ def choose_detectors(args):
return detectors_to_run return detectors_to_run
def apply_detector_results(slither, patches, detector_results): def apply_detector_results(slither, patches, detector_results):
'''
Apply slither detector results on contract files to generate patches
'''
for result in detector_results: for result in detector_results:
if result['check'] == 'unused-state': if result['check'] == 'unused-state':
unused_state.format(slither, patches, result['elements']) unused_state.format(slither, patches, result['elements'])
@ -194,7 +200,7 @@ def apply_detector_results(slither, patches, detector_results):
elif result['check'] == 'constant-function': elif result['check'] == 'constant-function':
constable_states.format(slither, patches, result['elements']) constable_states.format(slither, patches, result['elements'])
else: else:
logger.error(red("Not Supported Yet.")) logger.error(red(result['check'] + "detector not supported yet."))
sys.exit(-1) sys.exit(-1)
def get_number_of_slither_results (detector_results): def get_number_of_slither_results (detector_results):

@ -0,0 +1,24 @@
from os import listdir
from os.path import isfile, join
import subprocess
contracts_path = "../../smart-contracts-detectors-testing/most_used/contracts/"
slither_format_output_path = "./slither_format/tests/slither_format_output_most_used_contracts/"
def analyze_contract_with_slither_format():
for contract_file in contract_files:
run_slither_format(contract_file)
def run_slither_format(contract_name):
print("Running Slither Format on contract: " + contract_name)
command = "python3 -m slither_format " + contracts_path+contract_name
contract_slither_output_fd = open(slither_format_output_path+contract_name[:-21]+".txt","w+")
contract_slither_output_fd.write("Command run: " + command + "\n\n")
contract_slither_output_fd.flush()
result = subprocess.run(command, shell=True, stdout=contract_slither_output_fd, stderr=contract_slither_output_fd)
contract_slither_output_fd.close()
if __name__ == "__main__":
contract_files = [f for f in listdir(contracts_path) if f.endswith(".sol")]
print("Number of contract files: " + str(len(contract_files)))
analyze_contract_with_slither_format()
Loading…
Cancel
Save