@ -8,7 +8,7 @@ import os
import sys
import traceback
from pkg_resources import iter_entry_points
from pkg_resources import iter_entry_points , require
from slither . detectors . abstract_detector import ( AbstractDetector ,
DetectorClassification ,
@ -19,7 +19,8 @@ from slither.slither import Slither
logging . basicConfig ( )
logger = logging . getLogger ( " Slither " )
def output_to_markdown ( detector_classes ) :
def output_detectors ( detector_classes ) :
"""
Pretty print of the detectors to README . md
"""
@ -27,8 +28,6 @@ def output_to_markdown(detector_classes):
for detector in detector_classes :
argument = detector . ARGUMENT
# dont show the backdoor example
if argument == ' backdoor ' :
continue
help_info = detector . HELP
impact = detector . IMPACT
confidence = classification_txt [ detector . CONFIDENCE ]
@ -43,7 +42,27 @@ def output_to_markdown(detector_classes):
help_info ,
classification_txt [ impact ] ,
confidence ) )
idx = idx + 1
idx = idx + 1
def output_printers ( printer_classes ) :
"""
Pretty print of the printers to README . md
"""
printers_list = [ ]
for printer in printer_classes :
argument = printer . ARGUMENT
help_info = printer . HELP
printers_list . append ( ( argument , help_info ) )
print ( printers_list )
# Sort by name
printers_list = sorted ( printers_list , key = lambda element : ( element [ 0 ] ) )
idx = 1
for ( argument , help_info ) in printers_list :
print ( ' {} | ` {} ` | {} ' . format ( idx , argument , help_info ) )
idx = idx + 1
def process ( filename , args , detector_classes , printer_classes ) :
"""
@ -64,15 +83,13 @@ def process(filename, args, detector_classes, printer_classes):
results = [ ]
if printer_classes :
slither . run_printers ( ) # Currently printers does not return 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
elif detector_classes :
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 )
results . extend ( detector_results )
slither . run_printers ( ) # Currently printers does not return results
return results , analyzed_contracts_count
@ -164,8 +181,12 @@ def main_impl(all_detector_classes, all_printer_classes):
"""
args = parse_args ( all_detector_classes , all_printer_classes )
if args . markdown :
output_to_markdown ( all_detector_classes )
if args . list_detectors :
output_detectors ( all_detector_classes )
return
if args . list_printers :
output_printers ( all_printer_classes )
return
detector_classes = choose_detectors ( args , all_detector_classes )
@ -205,9 +226,6 @@ def main_impl(all_detector_classes, all_printer_classes):
( results_tmp , number_contracts_tmp ) = process ( filename , args , detector_classes , printer_classes )
number_contracts + = number_contracts_tmp
results + = results_tmp
# if args.json:
# output_json(results, args.json)
# exit(results)
else :
raise Exception ( " Unrecognised file/dir path: ' # {filename} ' " . format ( filename = filename ) )
@ -229,17 +247,48 @@ def main_impl(all_detector_classes, all_printer_classes):
def parse_args ( detector_classes , printer_classes ) :
parser = argparse . ArgumentParser ( description = ' Slither ' ,
usage = " slither.py contract.sol [flag] " ,
formatter_class = lambda prog : argparse . HelpFormatter ( prog , max_help_position = 35 ) )
usage = " slither.py contract.sol [flag] " )
parser . add_argument ( ' filename ' ,
help = ' contract.sol file ' )
parser . add_argument ( ' --version ' ,
help = ' displays the current version ' ,
version = require ( ' slither-analyzer ' ) [ 0 ] . version ,
action = ' version ' )
parser . add_argument ( ' --solc ' ,
help = ' solc path ' ,
action = ' store ' ,
default = ' solc ' )
parser . add_argument ( ' --detectors ' ,
help = ' Comma-separated list of detectors, defaults to all, '
' available detectors: {} ' . format ( ' , ' . join ( d . ARGUMENT for d in detector_classes ) ) ,
action = ' store ' ,
dest = ' detectors_to_run ' ,
default = ' all ' )
parser . add_argument ( ' --printers ' ,
help = ' Comma-separated list fo contract information printers, '
' defaults to contract-summary and can be disabled by using \' none \' , '
' available printers: {} ' . format ( ' , ' . join ( d . ARGUMENT for d in printer_classes ) ) ,
action = ' store ' ,
dest = ' printers_to_run ' ,
default = ' contract-summary ' )
parser . add_argument ( ' --output ' ,
help = ' Define output encoding ' ,
action = ' store ' ,
choices = [ ' stdout ' , ' json ' ] ,
default = ' stdout ' )
parser . add_argument ( ' --exclude-detectors ' ,
help = ' Comma-separated list of detectors that should be excluded ' ,
action = ' store ' ,
dest = ' detectors_to_exclude ' ,
default = ' ' )
parser . add_argument ( ' --solc-args ' ,
help = ' Add custom solc arguments. Example: --solc-args " --allow-path /tmp --evm-version byzantium " . ' ,
action = ' store ' ,
@ -280,34 +329,6 @@ def parse_args(detector_classes, printer_classes):
action = ' store_true ' ,
default = False )
for detector_cls in detector_classes :
detector_arg = ' --detect- {} ' . format ( detector_cls . ARGUMENT )
detector_help = ' {} ' . format ( detector_cls . HELP )
parser . add_argument ( detector_arg ,
help = detector_help ,
action = " append_const " ,
dest = " detectors_to_run " ,
const = detector_cls . ARGUMENT )
# Second loop so that the --exclude are shown after all the detectors
for detector_cls in detector_classes :
exclude_detector_arg = ' --exclude- {} ' . format ( detector_cls . ARGUMENT )
exclude_detector_help = ' Exclude {} detector ' . format ( detector_cls . ARGUMENT )
parser . add_argument ( exclude_detector_arg ,
help = exclude_detector_help ,
action = " append_const " ,
dest = " detectors_to_exclude " ,
const = detector_cls . ARGUMENT )
for printer_cls in printer_classes :
printer_arg = ' --printer- {} ' . format ( printer_cls . ARGUMENT )
printer_help = ' Print {} ' . format ( printer_cls . HELP )
parser . add_argument ( printer_arg ,
help = printer_help ,
action = " append_const " ,
dest = " printers_to_run " ,
const = printer_cls . ARGUMENT )
# debugger command
parser . add_argument ( ' --debug ' ,
help = argparse . SUPPRESS ,
@ -319,15 +340,44 @@ def parse_args(detector_classes, printer_classes):
action = " store_true " ,
default = False )
return parser . parse_args ( )
parser . add_argument ( ' --list-detectors ' ,
help = ' List available detectors ' ,
action = ' store_true ' ,
default = False )
parser . add_argument ( ' --list-printers ' ,
help = ' List available printers ' ,
action = ' store_true ' ,
default = False )
if len ( sys . argv ) == 1 :
parser . print_help ( sys . stderr )
sys . exit ( 1 )
args = parser . parse_args ( )
return args
def choose_detectors ( args , all_detector_classes ) :
# If detectors are specified, run only these ones
if args . detectors_to_run :
return [ d for d in all_detector_classes if d . ARGUMENT in args . detectors_to_run ]
detectors_to_run = all_detector_classes
detectors_to_run = [ ]
detectors = { d . ARGUMENT : d for d in all_detector_classes }
if args . detectors_to_run == ' all ' :
detectors_to_run = all_detector_classes
detectors_excluded = args . detectors_to_exclude . split ( ' , ' )
for d in detectors :
if d in detectors_excluded :
detectors_to_run . remove ( detectors [ d ] )
else :
for d in args . detectors_to_run . split ( ' , ' ) :
if d in detectors :
detectors_to_run . append ( detectors [ d ] )
else :
raise Exception ( ' Error: {} is not a detector ' . format ( d ) )
return detectors_to_run
if args . exclude_informational :
detectors_to_run = [ d for d in detectors_to_run if
@ -348,11 +398,18 @@ def choose_detectors(args, all_detector_classes):
def choose_printers ( args , all_printer_classes ) :
# by default, dont run any printer
printers_to_run = [ ]
if args . printers_to_run :
printers_to_run = [ p for p in all_printer_classes if
p . ARGUMENT in args . printers_to_run ]
# disable default printer
if args . printers_to_run == ' none ' :
return printers_to_run
printers = { p . ARGUMENT : p for p in all_printer_classes }
for p in args . printers_to_run . split ( ' , ' ) :
if p in printers :
printers_to_run . append ( printers [ p ] )
else :
raise Exception ( ' Error: {} is not a printer ' . format ( p ) )
return printers_to_run