Repository: crytic/slither

Issue:
Broken filter-paths option
Getting back a `AttributeError: 'list' object has no attribute 'split'` error when using the `--filter-paths` option. Full results off my run below:

```
$ slither contracts/ --solc-disable-warnings --exclude-low --exclude-informational --filter-paths dappsys
INFO:Detectors:
ReputationMiningCycleStorage.colonyNetworkAddress (contracts/ReputationMiningCycleStorage.sol#31) is never initialized. It is used in:
	- checkChildReputation (contracts/ReputationMiningCycleRespond.sol#318-340)
	- checkKey (contracts/ReputationMiningCycleRespond.sol#351-361)
	- getExpectedSkillIdAndAddress (contracts/ReputationMiningCycleRespond.sol#389-417)
	- getRelativeUpdateNumber (contracts/ReputationMiningCycleRespond.sol#604-616)
	- getChildAndParentNUpdatesForLogEntry (contracts/ReputationMiningCycleRespond.sol#618-630)
ReputationMiningCycleStorage.reputationUpdateLog (contracts/ReputationMiningCycleStorage.sol#35) is never initialized. It is used in:
	- checkUserOriginReputation (contracts/ReputationMiningCycleRespond.sol#296-316)
	- checkChildReputation (contracts/ReputationMiningCycleRespond.sol#318-340)
	- checkKeyLogEntry (contracts/ReputationMiningCycleRespond.sol#370-387)
	- proveValue (contracts/ReputationMiningCycleRespond.sol#524-600)
	- getChildAndParentNUpdatesForLogEntry (contracts/ReputationMiningCycleRespond.sol#618-630)
ReputationMiningCycleStorage.reputationHashSubmissions (contracts/ReputationMiningCycleStorage.sol#38) is never initialized. It is used in:
	- checkAdjacentReputation (contracts/ReputationMiningCycleRespond.sol#183-244)
	- confirmChallengeCompleted (contracts/ReputationMiningCycleRespond.sol#342-349)
	- proveBeforeReputationValue (contracts/ReputationMiningCycleRespond.sol#419-459)
	- proveAfterReputationValue (contracts/ReputationMiningCycleRespond.sol#461-489)
	- checkPreviousReputationInState (contracts/ReputationMiningCycleRespond.sol#632-655)
	- checkUserOriginReputationInState (contracts/ReputationMiningCycleRespond.sol#666-723)
	- checkChildReputationInState (contracts/ReputationMiningCycleRespond.sol#725-780)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#uninitialized-state-variables
INFO:Detectors:
ReputationMiningCycleRespond.buildReputationKey (contracts/ReputationMiningCycleRespond.sol#793-801) is declared view but contains assembly code
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#constant-functions-changing-the-state
INFO:Detectors:
Reentrancy in ReputationMiningCycleRespond.respondToChallenge (contracts/ReputationMiningCycleRespond.sol#103-177):
	External calls:
	- checkKey(u,b32) (contracts/ReputationMiningCycleRespond.sol#136)
	- performReputationCalculation(u) (contracts/ReputationMiningCycleRespond.sol#146)
	- checkChildReputation(u,b32,agreeStateSiblings,childReputationSiblings) (contracts/ReputationMiningCycleRespond.sol#153)
	State variables written after the call(s):
	- disputeRounds (contracts/ReputationMiningCycleRespond.sol#169)
	- disputeRounds (contracts/ReputationMiningCycleRespond.sol#171)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#reentrancy-vulnerabilities-1
INFO:Detectors:
branchNode in Data.insertAtEdge (contracts/PatriciaTree/Data.sol#105) is a local variable never initialiazed
edgeHashes in PatriciaTreeProofs.getImpliedRootFunctionality (contracts/PatriciaTree/PatriciaTreeProofs.sol#44) is a local variable never initialiazed
e in PatriciaTreeProofs.getImpliedRootFunctionality (contracts/PatriciaTree/PatriciaTreeProofs.sol#42) is a local variable never initialiazed
nChildUpdates in ReputationMiningCycleRespond.getChildAndParentNUpdatesForLogEntry (contracts/ReputationMiningCycleRespond.sol#622) is a local variable never initialiazed
e in Data.insert (contracts/PatriciaTree/Data.sol#70) is a local variable never initialiazed
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#uninitialized-local-variables
ERROR:root:Error in contracts/
ERROR:root:Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/slither/__main__.py", line 582, in main_impl
    (results_tmp, number_contracts_tmp) = process(filename, args, detector_classes, printer_classes)
  File "/usr/local/lib/python3.7/site-packages/slither/__main__.py", line 48, in process
    args.filter_paths = parse_filter_paths(args)
  File "/usr/local/lib/python3.7/site-packages/slither/__main__.py", line 253, in parse_filter_paths
    return args.filter_paths.split(',')
AttributeError: 'list' object has no attribute 'split'
```


Discussion:

Resolving patch:
diff --git a/slither/__main__.py b/slither/__main__.py
--- a/slither/__main__.py
+++ b/slither/__main__.py
@@ -22,7 +22,8 @@
 from slither.utils.colors import red, yellow, set_colorization_enabled
 from slither.utils.command_line import (output_detectors, output_results_to_markdown,
                                         output_detectors_json, output_printers,
-                                        output_to_markdown, output_wiki)
+                                        output_to_markdown, output_wiki, defaults_flag_in_config,
+                                        read_config_file)
 from crytic_compile import is_supported
 from slither.exceptions import SlitherException
 
@@ -45,7 +46,6 @@ def process(filename, args, detector_classes, printer_classes):
     ast = '--ast-compact-json'
     if args.legacy_ast:
         ast = '--ast-json'
-    args.filter_paths = parse_filter_paths(args)
     slither = Slither(filename,
                       ast_format=ast,
                       **vars(args))
@@ -84,12 +84,7 @@ def process_files(filenames, args, detector_classes, printer_classes):
             all_contracts.append(contract_loaded['ast'])
 
     slither = Slither(all_contracts,
-                      solc=args.solc,
-                      disable_solc_warnings=args.disable_solc_warnings,
-                      solc_arguments=args.solc_args,
-                      filter_paths=parse_filter_paths(args),
-                      triage_mode=args.triage_mode,
-                      exclude_dependencies=args.exclude_dependencies)
+                      **vars(args))
 
     return _process(slither, detector_classes, printer_classes)
 
@@ -258,33 +253,6 @@ def parse_filter_paths(args):
         return args.filter_paths.split(',')
     return []
 
-# Those are the flags shared by the command line and the config file
-defaults_flag_in_config = {
-    'detectors_to_run': 'all',
-    'printers_to_run': None,
-    'detectors_to_exclude': None,
-    'exclude_dependencies': False,
-    'exclude_optimization': False,
-    'exclude_informational': False,
-    'exclude_low': False,
-    'exclude_medium': False,
-    'exclude_high': False,
-    'solc': 'solc',
-    'solc_args': None,
-    'disable_solc_warnings': False,
-    'json': None,
-    'truffle_version': None,
-    'disable_color': False,
-    'filter_paths': None,
-    'truffle_ignore_compile': False,
-    'truffle_build_directory': 'build/contracts',
-    'embark_ignore_compile': False,
-    'embark_overwrite_config': False,
-    # debug command
-    'legacy_ast': False,
-    'ignore_return_value': False
-    }
-
 def parse_args(detector_classes, printer_classes):
     parser = argparse.ArgumentParser(description='Slither. For usage information, see https://github.com/crytic/slither/wiki/Usage',
                                      usage="slither.py contract.sol [flag]")
@@ -451,19 +419,9 @@ def parse_args(detector_classes, printer_classes):
         sys.exit(1)
 
     args = parser.parse_args()
+    read_config_file(args)
 
-    if os.path.isfile(args.config_file):
-        try:
-            with open(args.config_file) as f:
-                config = json.load(f)
-                for key, elem in config.items():
-                    if key not in defaults_flag_in_config:
-                        logger.info(yellow('{} has an unknown key: {} : {}'.format(args.config_file, key, elem)))
-                        continue
-                    if getattr(args, key) == defaults_flag_in_config[key]:
-                        setattr(args, key, elem)
-        except json.decoder.JSONDecodeError as e:
-            logger.error(red('Impossible to read {}, please check the file {}'.format(args.config_file, e)))
+    args.filter_paths = parse_filter_paths(args)
 
     return args
 
@@ -536,6 +494,8 @@ def main_impl(all_detector_classes, all_printer_classes):
     :param all_detector_classes: A list of all detectors that can be included/excluded.
     :param all_printer_classes: A list of all printers that can be included.
     """
+    # Set logger of Slither to info, to catch warnings related to the arg parsing
+    logger.setLevel(logging.INFO)
     args = parse_args(all_detector_classes, all_printer_classes)
 
     # Set colorization option
diff --git a/slither/utils/command_line.py b/slither/utils/command_line.py
--- a/slither/utils/command_line.py
+++ b/slither/utils/command_line.py
@@ -1,8 +1,49 @@
+import os
+import logging
 import json
 from collections import defaultdict
 from prettytable import PrettyTable
+from crytic_compile.cryticparser.defaults import defaults_flag_in_config as defaults_flag_in_config_crytic_compile
 
 from slither.detectors.abstract_detector import classification_txt
+from .colors import yellow, red
+
+logger = logging.getLogger("Slither")
+
+# Those are the flags shared by the command line and the config file
+defaults_flag_in_config = {
+    'detectors_to_run': 'all',
+    'printers_to_run': None,
+    'detectors_to_exclude': None,
+    'exclude_dependencies': False,
+    'exclude_informational': False,
+    'exclude_optimization': False,
+    'exclude_low': False,
+    'exclude_medium': False,
+    'exclude_high': False,
+    'json': None,
+    'disable_color': False,
+    'filter_paths': None,
+    # debug command
+    'legacy_ast': False,
+    'ignore_return_value': False,
+    **defaults_flag_in_config_crytic_compile
+    }
+
+def read_config_file(args):
+    if os.path.isfile(args.config_file):
+        try:
+            with open(args.config_file) as f:
+                config = json.load(f)
+                for key, elem in config.items():
+                    if key not in defaults_flag_in_config:
+                        logger.info(yellow('{} has an unknown key: {} : {}'.format(args.config_file, key, elem)))
+                        continue
+                    if getattr(args, key) == defaults_flag_in_config[key]:
+                        setattr(args, key, elem)
+        except json.decoder.JSONDecodeError as e:
+            logger.error(red('Impossible to read {}, please check the file {}'.format(args.config_file, e)))
+
 
 def output_to_markdown(detector_classes, printer_classes, filter_wiki):
 


Test patch: