From ecebd0414d205abea15a40c463c88877c5db1226 Mon Sep 17 00:00:00 2001 From: Josselin Date: Mon, 11 Feb 2019 11:15:24 -0500 Subject: [PATCH] WIP database --- examples/printers/call_graph.sol.dot | 4 +-- slither/__main__.py | 9 ++++-- slither/core/slither_core.py | 10 +++++++ slither/detectors/abstract_detector.py | 29 ++++++++++++++----- slither/detectors/all_detectors.py | 4 +-- .../detectors/attributes/const_functions.py | 4 +-- .../detectors/attributes/constant_pragma.py | 3 +- .../detectors/attributes/incorrect_solc.py | 3 +- slither/detectors/attributes/locked_ether.py | 3 +- slither/detectors/examples/backdoor.py | 4 +-- slither/detectors/functions/arbitrary_send.py | 5 +--- .../detectors/functions/external_function.py | 7 +---- slither/detectors/functions/suicidal.py | 4 +-- .../naming_convention/naming_convention.py | 15 +--------- .../detectors/operations/block_timestamp.py | 5 +--- .../detectors/operations/low_level_calls.py | 8 +---- .../operations/unused_return_values.py | 3 +- slither/detectors/reentrancy/reentrancy.py | 2 +- .../detectors/reentrancy/reentrancy_benign.py | 5 ++-- .../detectors/reentrancy/reentrancy_eth.py | 5 ++-- .../reentrancy_read_before_write.py | 5 ++-- slither/detectors/shadowing/abstract.py | 3 +- .../detectors/shadowing/builtin_symbols.py | 4 +-- slither/detectors/shadowing/local.py | 4 +-- slither/detectors/shadowing/state.py | 3 +- slither/detectors/statements/assembly.py | 7 +---- slither/detectors/statements/calls_in_loop.py | 4 +-- .../statements/controlled_delegatecall.py | 3 +- .../statements/incorrect_strict_equality.py | 5 +--- slither/detectors/statements/tx_origin.py | 4 +-- .../possible_const_state_variables.py | 3 +- .../uninitialized_local_variables.py | 3 +- .../uninitialized_state_variables.py | 3 +- .../uninitialized_storage_variables.py | 5 +--- .../variables/unused_state_variables.py | 6 +--- slither/slither.py | 2 ++ 36 files changed, 77 insertions(+), 119 deletions(-) diff --git a/examples/printers/call_graph.sol.dot b/examples/printers/call_graph.sol.dot index 5677b7a40..723278180 100644 --- a/examples/printers/call_graph.sol.dot +++ b/examples/printers/call_graph.sol.dot @@ -11,11 +11,11 @@ label = "ContractA" subgraph cluster_63_ContractB { label = "ContractB" "63_my_second_func_b" [label="my_second_func_b"] +"63_my_func_b" [label="my_func_b"] "63_my_func_a" [label="my_func_a"] "63_constructor" [label="constructor"] -"63_my_func_b" [label="my_func_b"] -"63_my_func_b" -> "63_my_second_func_b" "63_my_func_a" -> "63_my_second_func_b" +"63_my_func_b" -> "63_my_second_func_b" } subgraph cluster_solidity { label = "[Solidity]" diff --git a/slither/__main__.py b/slither/__main__.py index 34b11953e..9ccca453c 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -18,7 +18,7 @@ from slither.detectors.abstract_detector import (AbstractDetector, from slither.printers import all_printers from slither.printers.abstract_printer import AbstractPrinter from slither.slither import Slither -from slither.utils.colors import red, set_colorization_enabled +from slither.utils.colors import red, yellow, set_colorization_enabled from slither.utils.command_line import (output_detectors, output_detectors_json, output_printers, output_to_markdown, output_wiki) @@ -118,8 +118,11 @@ def process_files(filenames, args, detector_classes, printer_classes): ################################################################################### def output_json(results, filename): - with open(filename, 'w', encoding='utf8') as f: - json.dump(results, f) + if os.path.isfile(filename): + logger.info(yellow(f'{filename} exists already, the overwrite is prevented')) + else: + with open(filename, 'w', encoding='utf8') as f: + json.dump(results, f) # endregion ################################################################################### diff --git a/slither/core/slither_core.py b/slither/core/slither_core.py index 31714d46b..769028fbc 100644 --- a/slither/core/slither_core.py +++ b/slither/core/slither_core.py @@ -4,6 +4,7 @@ import os from slither.core.context.context import Context from slither.slithir.operations import InternalCall +import json class Slither(Context): """ @@ -109,3 +110,12 @@ class Slither(Context): for c in self.contracts: for f in c.functions: f.cfg_to_dot(os.path.join(d, '{}.{}.dot'.format(c.name, f.name))) + + def valid_result(self, r): + return r['description'] not in self._previous_descriptions + + def load_previous_results(self, filename='slither.db.json'): + if os.path.isfile(filename): + with open(filename) as f: + data = json.load(f) + self._previous_descriptions = [r['description'] for r in data] diff --git a/slither/detectors/abstract_detector.py b/slither/detectors/abstract_detector.py index aff8840a6..fcd6fb205 100644 --- a/slither/detectors/abstract_detector.py +++ b/slither/detectors/abstract_detector.py @@ -86,18 +86,33 @@ class AbstractDetector(metaclass=abc.ABCMeta): DetectorClassification.INFORMATIONAL]: raise IncorrectDetectorInitialization('CONFIDENCE is not initialized {}'.format(self.__class__.__name__)) - def log(self, info): - if self.logger: - info = "\n"+info - if self.WIKI != '': - info += 'Reference: {}'.format(self.WIKI) - self.logger.info(self.color(info)) +# def log(self, info): +# if self.logger: +# info = "\n"+info +# if self.WIKI != '': +# info += 'Reference: {}'.format(self.WIKI) +# self.logger.info(self.color(info)) + + def _log(self, info): + self.logger.info(self.color(info)) @abc.abstractmethod - def detect(self): + def _detect(self): """TODO Documentation""" return + def detect(self): + results = self._detect() + results = [r for r in results if self.slither.valid_result(r)] + if results: + if self.logger: + for result in results: + info = "\n"+result['description'] + info += 'Reference: {}'.format(self.WIKI) + self._log(info) + return results + + @property def color(self): return classification_colors[self.IMPACT] diff --git a/slither/detectors/all_detectors.py b/slither/detectors/all_detectors.py index 2b77a52d7..8134d7059 100644 --- a/slither/detectors/all_detectors.py +++ b/slither/detectors/all_detectors.py @@ -28,5 +28,5 @@ from .shadowing.builtin_symbols import BuiltinSymbolShadowing from .operations.block_timestamp import Timestamp from .statements.calls_in_loop import MultipleCallsInLoop from .statements.incorrect_strict_equality import IncorrectStrictEquality - - +# +# diff --git a/slither/detectors/attributes/const_functions.py b/slither/detectors/attributes/const_functions.py index 26ac42a20..d454b5827 100644 --- a/slither/detectors/attributes/const_functions.py +++ b/slither/detectors/attributes/const_functions.py @@ -41,7 +41,7 @@ All the calls to `get` reverts, breaking Bob's smart contract execution.''' WIKI_RECOMMENDATION = 'Ensure that the attributes of contracts compiled prior Solidity 0.5.0 are correct.' - def detect(self): + def _detect(self): """ Detect the constant function changing the state Recursively visit the calls @@ -58,7 +58,6 @@ All the calls to `get` reverts, breaking Bob's smart contract execution.''' attr = 'view' if f.view else 'pure' info = '{}.{} ({}) is declared {} but contains assembly code\n' info = info.format(f.contract.name, f.name, f.source_mapping_str, attr) - self.log(info) json = self.generate_json_result(info) self.add_function_to_json(f, json) json['elements'] = [{'type': 'info', @@ -73,7 +72,6 @@ All the calls to `get` reverts, breaking Bob's smart contract execution.''' for variable_written in variables_written: info += '\t- {}.{}\n'.format(variable_written.contract.name, variable_written.name) - self.log(info) json = self.generate_json_result(info) diff --git a/slither/detectors/attributes/constant_pragma.py b/slither/detectors/attributes/constant_pragma.py index eaa62e83d..6c04ddfc2 100644 --- a/slither/detectors/attributes/constant_pragma.py +++ b/slither/detectors/attributes/constant_pragma.py @@ -22,7 +22,7 @@ class ConstantPragma(AbstractDetector): WIKI_DESCRIPTION = 'Detect if different Solidity versions are used.' WIKI_RECOMMENDATION = 'Use one Solidity version.' - def detect(self): + def _detect(self): results = [] pragma = self.slither.pragma_directives versions = [p.version for p in pragma] @@ -33,7 +33,6 @@ class ConstantPragma(AbstractDetector): info += "\t- Version used: {}\n".format([str(v) for v in versions]) for p in pragma: info += "\t- {} declares {}\n".format(p.source_mapping_str, str(p)) - self.log(info) json = self.generate_json_result(info) # follow the same format than add_nodes_to_json diff --git a/slither/detectors/attributes/incorrect_solc.py b/slither/detectors/attributes/incorrect_solc.py index f10929958..8e986884d 100644 --- a/slither/detectors/attributes/incorrect_solc.py +++ b/slither/detectors/attributes/incorrect_solc.py @@ -62,7 +62,7 @@ We recommend avoiding complex pragma statement.''' return self._check_version(version_left) else: return self.COMPLEX_PRAGMA - def detect(self): + def _detect(self): """ Detects pragma statements that allow for outdated solc versions. :return: Returns the relevant JSON data for the findings. @@ -88,7 +88,6 @@ We recommend avoiding complex pragma statement.''' info = "Detected issues with version pragma in {}:\n".format(self.filename) for (reason, p) in disallowed_pragmas: info += "\t- {} ({}): {}\n".format(p, p.source_mapping_str, reason) - self.log(info) json = self.generate_json_result(info) diff --git a/slither/detectors/attributes/locked_ether.py b/slither/detectors/attributes/locked_ether.py index d7aa73dd2..bde8f67cf 100644 --- a/slither/detectors/attributes/locked_ether.py +++ b/slither/detectors/attributes/locked_ether.py @@ -65,7 +65,7 @@ Every ethers send to `Locked` will be lost.''' return True - def detect(self): + def _detect(self): results = [] for contract in self.slither.contracts_derived: @@ -82,7 +82,6 @@ Every ethers send to `Locked` will be lost.''' info = txt.format(self.filename, contract.name, [f.name for f in funcs_payable]) - self.log(info) json = self.generate_json_result(info) self.add_functions_to_json(funcs_payable, json) diff --git a/slither/detectors/examples/backdoor.py b/slither/detectors/examples/backdoor.py index a1c6d6c54..c0fcf7f03 100644 --- a/slither/detectors/examples/backdoor.py +++ b/slither/detectors/examples/backdoor.py @@ -18,7 +18,7 @@ class Backdoor(AbstractDetector): WIKI_EXPLOIT_SCENARIO = '..' WIKI_RECOMMENDATION = '..' - def detect(self): + def _detect(self): results = [] for contract in self.slither.contracts_derived: @@ -28,8 +28,6 @@ class Backdoor(AbstractDetector): # Info to be printed info = 'Backdoor function found in {}.{} ({})\n' info = info.format(contract.name, f.name, f.source_mapping_str) - # Print the info - self.log(info) # Add the result in result json = self.generate_json_result(info) self.add_function_to_json(f, json) diff --git a/slither/detectors/functions/arbitrary_send.py b/slither/detectors/functions/arbitrary_send.py index bba2ce535..a44eefd42 100644 --- a/slither/detectors/functions/arbitrary_send.py +++ b/slither/detectors/functions/arbitrary_send.py @@ -100,7 +100,7 @@ Bob calls `setDestination` and `withdraw`. As a result he withdraws the contract ret.append((f, nodes)) return ret - def detect(self): + def _detect(self): """ """ results = [] @@ -117,9 +117,6 @@ Bob calls `setDestination` and `withdraw`. As a result he withdraws the contract for node in nodes: info += '\t- {} ({})\n'.format(node.expression, node.source_mapping_str) - self.log(info) - - json = self.generate_json_result(info) self.add_function_to_json(func, json) self.add_nodes_to_json(nodes, json) diff --git a/slither/detectors/functions/external_function.py b/slither/detectors/functions/external_function.py index 11cafdfad..a9a456b4c 100644 --- a/slither/detectors/functions/external_function.py +++ b/slither/detectors/functions/external_function.py @@ -96,11 +96,9 @@ class ExternalFunction(AbstractDetector): for function in derived_contract.functions if function.full_name == base_most_function.full_name] - def detect(self): + def _detect(self): results = [] - all_info = '' - # Create a set to track contracts with dynamic calls. All contracts with dynamic calls could potentially be # calling functions internally, and thus we can't assume any function in such contracts isn't called by them. dynamic_call_contracts = set() @@ -171,12 +169,9 @@ class ExternalFunction(AbstractDetector): info = txt.format(function_definition.contract.name, function_definition.name, function_definition.source_mapping_str) - all_info += info json = self.generate_json_result(info) self.add_function_to_json(function_definition, json) results.append(json) - if all_info != '': - self.log(all_info) return results diff --git a/slither/detectors/functions/suicidal.py b/slither/detectors/functions/suicidal.py index 466cc535c..501952f6b 100644 --- a/slither/detectors/functions/suicidal.py +++ b/slither/detectors/functions/suicidal.py @@ -64,7 +64,7 @@ Bob calls `kill` and destruct the contract.''' ret.append(f) return ret - def detect(self): + def _detect(self): """ Detect the suicidal functions """ results = [] @@ -77,8 +77,6 @@ Bob calls `kill` and destruct the contract.''' func.name, func.source_mapping_str) - self.log(info) - json = self.generate_json_result(info) self.add_function_to_json(func, json) results.append(json) diff --git a/slither/detectors/naming_convention/naming_convention.py b/slither/detectors/naming_convention/naming_convention.py index 5d2b873ac..a6b5d72f3 100644 --- a/slither/detectors/naming_convention/naming_convention.py +++ b/slither/detectors/naming_convention/naming_convention.py @@ -51,16 +51,14 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 def should_avoid_name(name): return re.search('^[lOI]$', name) is not None - def detect(self): + def _detect(self): results = [] - all_info = '' for contract in self.contracts: if not self.is_cap_words(contract.name): info = "Contract '{}' ({}) is not in CapWords\n".format(contract.name, contract.source_mapping_str) - all_info += info json = self.generate_json_result(info) elem = dict() @@ -78,7 +76,6 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 if not self.is_cap_words(struct.name): info = "Struct '{}.{}' ({}) is not in CapWords\n" info = info.format(struct.contract.name, struct.name, struct.source_mapping_str) - all_info += info json = self.generate_json_result(info) elem = dict() @@ -95,7 +92,6 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 if not self.is_cap_words(event.name): info = "Event '{}.{}' ({}) is not in CapWords\n" info = info.format(event.contract.name, event.name, event.source_mapping_str) - all_info += info json = self.generate_json_result(info) elem = dict() @@ -113,7 +109,6 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 if not self.is_mixed_case(func.name): info = "Function '{}.{}' ({}) is not in mixedCase\n" info = info.format(func.contract.name, func.name, func.source_mapping_str) - all_info += info json = self.generate_json_result(info) elem = dict() @@ -135,7 +130,6 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 argument.function.contract.name, argument.function, argument.source_mapping_str) - all_info += info json = self.generate_json_result(info) elem = dict() @@ -154,7 +148,6 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 if not self.is_upper_case_with_underscores(var.name): info = "Variable '{}.{}' ({}) used l, O, I, which should not be used\n" info = info.format(var.contract.name, var.name, var.source_mapping_str) - all_info += info json = self.generate_json_result(info) elem = dict() @@ -173,7 +166,6 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 if not self.is_upper_case_with_underscores(var.name): info = "Constant '{}.{}' ({}) is not in UPPER_CASE_WITH_UNDERSCORES\n" info = info.format(var.contract.name, var.name, var.source_mapping_str) - all_info += info json = self.generate_json_result(info) elem = dict() @@ -192,7 +184,6 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 if not correct_naming: info = "Variable '{}.{}' ({}) is not in mixedCase\n" info = info.format(var.contract.name, var.name, var.source_mapping_str) - all_info += info json = self.generate_json_result(info) elem = dict() @@ -210,7 +201,6 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 if not self.is_cap_words(enum.name): info = "Enum '{}.{}' ({}) is not in CapWords\n" info = info.format(enum.contract.name, enum.name, enum.source_mapping_str) - all_info += info json = self.generate_json_result(info) elem = dict() @@ -231,7 +221,6 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 info = info.format(modifier.contract.name, modifier.name, modifier.source_mapping_str) - all_info += info json = self.generate_json_result(info) elem = dict() @@ -242,7 +231,5 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 json['elements'] = [elem] results.append(json) - if all_info != '': - self.log(all_info) return results diff --git a/slither/detectors/operations/block_timestamp.py b/slither/detectors/operations/block_timestamp.py index fcb7d7b50..7c2f61a6b 100644 --- a/slither/detectors/operations/block_timestamp.py +++ b/slither/detectors/operations/block_timestamp.py @@ -67,7 +67,7 @@ class Timestamp(AbstractDetector): ret.append((f, nodes)) return ret - def detect(self): + def _detect(self): """ """ results = [] @@ -84,9 +84,6 @@ class Timestamp(AbstractDetector): for node in nodes: info += '\t- {} ({})\n'.format(node.expression, node.source_mapping_str) - self.log(info) - - json = self.generate_json_result(info) self.add_function_to_json(func, json) self.add_nodes_to_json(nodes, json) diff --git a/slither/detectors/operations/low_level_calls.py b/slither/detectors/operations/low_level_calls.py index 57451d46b..6425f087a 100644 --- a/slither/detectors/operations/low_level_calls.py +++ b/slither/detectors/operations/low_level_calls.py @@ -41,11 +41,10 @@ class LowLevelCalls(AbstractDetector): ret.append((f, assembly_nodes)) return ret - def detect(self): + def _detect(self): """ Detect the functions that use low level calls """ results = [] - all_info = '' for c in self.contracts: values = self.detect_low_level_calls(c) for func, nodes in values: @@ -53,15 +52,10 @@ class LowLevelCalls(AbstractDetector): info = info.format(func.contract.name, func.name, func.source_mapping_str) for node in nodes: info += "\t-{} {}\n".format(str(node.expression), node.source_mapping_str) - all_info += info json = self.generate_json_result(info) self.add_function_to_json(func, json) self.add_nodes_to_json(nodes, json) results.append(json) - - - if all_info != '': - self.log(all_info) return results diff --git a/slither/detectors/operations/unused_return_values.py b/slither/detectors/operations/unused_return_values.py index b48921b9e..3d8f8777b 100644 --- a/slither/detectors/operations/unused_return_values.py +++ b/slither/detectors/operations/unused_return_values.py @@ -58,7 +58,7 @@ contract MyConc{ return [nodes_origin[value].node for value in values_returned] - def detect(self): + def _detect(self): """ Detect unused high level calls that return a value but are never used """ results = [] @@ -74,7 +74,6 @@ contract MyConc{ f.source_mapping_str) for node in unused_return: info += "\t-{} ({})\n".format(node.expression, node.source_mapping_str) - self.log(info) json = self.generate_json_result(info) self.add_function_to_json(f, json) diff --git a/slither/detectors/reentrancy/reentrancy.py b/slither/detectors/reentrancy/reentrancy.py index 74dbab7b6..80b06c26b 100644 --- a/slither/detectors/reentrancy/reentrancy.py +++ b/slither/detectors/reentrancy/reentrancy.py @@ -186,7 +186,7 @@ class Reentrancy(AbstractDetector): self._explore(function.entry_point, []) function.context[self.KEY] = True - def detect(self): + def _detect(self): """ """ # if a node was already visited by another path diff --git a/slither/detectors/reentrancy/reentrancy_benign.py b/slither/detectors/reentrancy/reentrancy_benign.py index 719512a9f..0ca742dc6 100644 --- a/slither/detectors/reentrancy/reentrancy_benign.py +++ b/slither/detectors/reentrancy/reentrancy_benign.py @@ -71,11 +71,11 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr result[finding_key] = list(set(result[finding_key] + finding_vars)) return result - def detect(self): + def _detect(self): """ """ - super().detect() + super()._detect() reentrancies = self.find_reentrancies() results = [] @@ -96,7 +96,6 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr info += '\tState variables written after the call(s):\n' for (v, node) in varsWritten: info += '\t- {} ({})\n'.format(v, node.source_mapping_str) - self.log(info) sending_eth_json = [] if calls != send_eth: diff --git a/slither/detectors/reentrancy/reentrancy_eth.py b/slither/detectors/reentrancy/reentrancy_eth.py index 515fb3c46..8a43370b1 100644 --- a/slither/detectors/reentrancy/reentrancy_eth.py +++ b/slither/detectors/reentrancy/reentrancy_eth.py @@ -73,10 +73,10 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m result[finding_key] = list(set(result[finding_key] + finding_vars)) return result - def detect(self): + def _detect(self): """ """ - super().detect() + super()._detect() reentrancies = self.find_reentrancies() @@ -102,7 +102,6 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m info += '\tState variables written after the call(s):\n' for (v, node) in varsWritten: info += '\t- {} ({})\n'.format(v, node.source_mapping_str) - self.log(info) sending_eth_json = [] if calls != send_eth: diff --git a/slither/detectors/reentrancy/reentrancy_read_before_write.py b/slither/detectors/reentrancy/reentrancy_read_before_write.py index 92c1fb147..38b75eea6 100644 --- a/slither/detectors/reentrancy/reentrancy_read_before_write.py +++ b/slither/detectors/reentrancy/reentrancy_read_before_write.py @@ -70,11 +70,11 @@ Do not report reentrancies that involve ethers (see `reentrancy-eth`)''' result[finding_key] = list(set(result[finding_key] + finding_vars)) return result - def detect(self): + def _detect(self): """ """ - super().detect() + super()._detect() reentrancies = self.find_reentrancies() results = [] @@ -90,7 +90,6 @@ Do not report reentrancies that involve ethers (see `reentrancy-eth`)''' info += '\tState variables written after the call(s):\n' for (v, node) in varsWritten: info += '\t- {} ({})\n'.format(v, node.source_mapping_str) - self.log(info) sending_eth_json = [] diff --git a/slither/detectors/shadowing/abstract.py b/slither/detectors/shadowing/abstract.py index 5115a3f3f..1b31b0c71 100644 --- a/slither/detectors/shadowing/abstract.py +++ b/slither/detectors/shadowing/abstract.py @@ -50,7 +50,7 @@ contract DerivedContract is BaseContract{ return ret - def detect(self): + def _detect(self): """ Detect shadowing Recursively visit the calls @@ -72,7 +72,6 @@ contract DerivedContract is BaseContract{ info += "\t- {}.{} ({})\n".format(var.contract.name, var.name, var.source_mapping_str) - self.log(info) json = self.generate_json_result(info) self.add_variables_to_json(all_variables, json) diff --git a/slither/detectors/shadowing/builtin_symbols.py b/slither/detectors/shadowing/builtin_symbols.py index 2cb4c4471..fca17ad9b 100644 --- a/slither/detectors/shadowing/builtin_symbols.py +++ b/slither/detectors/shadowing/builtin_symbols.py @@ -111,7 +111,7 @@ contract Bug { return result - def detect(self): + def _detect(self): """ Detect shadowing of built-in symbols Recursively visit the calls @@ -140,8 +140,6 @@ contract Bug { shadow_type, shadow_object.source_mapping_str, shadow_object.name) - # Print relevant information to the log - self.log(info) # Generate relevant JSON data for this shadowing definition. json = self.generate_json_result(info) diff --git a/slither/detectors/shadowing/local.py b/slither/detectors/shadowing/local.py index 4dfbb3443..c8350af39 100644 --- a/slither/detectors/shadowing/local.py +++ b/slither/detectors/shadowing/local.py @@ -89,7 +89,7 @@ contract Bug { return result - def detect(self): + def _detect(self): """ Detect shadowing local variables Recursively visit the calls @@ -116,8 +116,6 @@ contract Bug { overshadowed_entry[0], overshadowed_entry[2].source_mapping_str) - # Print relevant information to the log - self.log(info) # Generate relevant JSON data for this shadowing definition. json = self.generate_json_result(info) diff --git a/slither/detectors/shadowing/state.py b/slither/detectors/shadowing/state.py index 096d5107f..0fbb477bf 100644 --- a/slither/detectors/shadowing/state.py +++ b/slither/detectors/shadowing/state.py @@ -61,7 +61,7 @@ contract DerivedContract is BaseContract{ ret.append([var] + shadow) return ret - def detect(self): + def _detect(self): """ Detect shadowing Recursively visit the calls @@ -83,7 +83,6 @@ contract DerivedContract is BaseContract{ info += "\t- {}.{} ({})\n".format(var.contract.name, var.name, var.source_mapping_str) - self.log(info) json = self.generate_json_result(info) self.add_variables_to_json(all_variables, json) diff --git a/slither/detectors/statements/assembly.py b/slither/detectors/statements/assembly.py index b770456bc..df63f0df5 100644 --- a/slither/detectors/statements/assembly.py +++ b/slither/detectors/statements/assembly.py @@ -44,11 +44,10 @@ class Assembly(AbstractDetector): ret.append((f, assembly_nodes)) return ret - def detect(self): + def _detect(self): """ Detect the functions that use inline assembly """ results = [] - all_info = '' for c in self.contracts: values = self.detect_assembly(c) for func, nodes in values: @@ -58,13 +57,9 @@ class Assembly(AbstractDetector): for node in nodes: info += "\t- {}\n".format(node.source_mapping_str) - all_info += info - json = self.generate_json_result(info) self.add_function_to_json(func, json) self.add_nodes_to_json(nodes, json) results.append(json) - if all_info != '': - self.log(all_info) return results diff --git a/slither/detectors/statements/calls_in_loop.py b/slither/detectors/statements/calls_in_loop.py index 2e5dbf9c7..8767d7ce1 100644 --- a/slither/detectors/statements/calls_in_loop.py +++ b/slither/detectors/statements/calls_in_loop.py @@ -78,7 +78,7 @@ If one of the destinations has a fallback function which reverts, `bad` will alw return ret - def detect(self): + def _detect(self): """ """ results = [] @@ -91,8 +91,6 @@ If one of the destinations has a fallback function which reverts, `bad` will alw info += "\t- {} ({})\n".format(node.expression, node.source_mapping_str) - self.log(info) - json = self.generate_json_result(info) self.add_function_to_json(func, json) self.add_nodes_to_json([node], json) diff --git a/slither/detectors/statements/controlled_delegatecall.py b/slither/detectors/statements/controlled_delegatecall.py index e1feadab9..900fe0915 100644 --- a/slither/detectors/statements/controlled_delegatecall.py +++ b/slither/detectors/statements/controlled_delegatecall.py @@ -37,7 +37,7 @@ Bob calls `delegate` and delegate the execution to its malicious contract. As a ret.append(node) return ret - def detect(self): + def _detect(self): results = [] for contract in self.slither.contracts: @@ -50,7 +50,6 @@ Bob calls `delegate` and delegate the execution to its malicious contract. As a info = info.format(contract.name, f.name, f.source_mapping_str) for node in nodes: info += '\t{} ({})\n'.format(node.expression, node.source_mapping_str) - self.log(info) json = self.generate_json_result(info) self.add_function_to_json(f, json) diff --git a/slither/detectors/statements/incorrect_strict_equality.py b/slither/detectors/statements/incorrect_strict_equality.py index 786f7d650..fe2ae895b 100644 --- a/slither/detectors/statements/incorrect_strict_equality.py +++ b/slither/detectors/statements/incorrect_strict_equality.py @@ -102,7 +102,7 @@ contract Crowdsale{ return results - def detect(self): + def _detect(self): results = [] for c in self.slither.contracts_derived: @@ -126,7 +126,4 @@ contract Crowdsale{ self.add_nodes_to_json(nodes, json) results.append(json) - if info: - self.log(info) - return results diff --git a/slither/detectors/statements/tx_origin.py b/slither/detectors/statements/tx_origin.py index e4f01e764..3f1c938cd 100644 --- a/slither/detectors/statements/tx_origin.py +++ b/slither/detectors/statements/tx_origin.py @@ -58,7 +58,7 @@ Bob is the owner of `TxOrigin`. Bob calls Eve's contract. Eve's contact calls `T ret.append((f, bad_tx_nodes)) return ret - def detect(self): + def _detect(self): """ Detect the functions that use tx.origin in a conditional node """ results = [] @@ -71,8 +71,6 @@ Bob is the owner of `TxOrigin`. Bob calls Eve's contract. Eve's contact calls `T for node in nodes: info += "\t- {} ({})\n".format(node.expression, node.source_mapping_str) - self.log(info) - json = self.generate_json_result(info) self.add_function_to_json(func, json) self.add_nodes_to_json(nodes, json) diff --git a/slither/detectors/variables/possible_const_state_variables.py b/slither/detectors/variables/possible_const_state_variables.py index d46912374..9cdc485aa 100644 --- a/slither/detectors/variables/possible_const_state_variables.py +++ b/slither/detectors/variables/possible_const_state_variables.py @@ -63,7 +63,7 @@ class ConstCandidateStateVars(AbstractDetector): - def detect(self): + def _detect(self): """ Detect state variables that could be const """ results = [] @@ -93,5 +93,4 @@ class ConstCandidateStateVars(AbstractDetector): json = self.generate_json_result(all_info) self.add_variables_to_json(constable_variables, json) results.append(json) - self.log(all_info) return results diff --git a/slither/detectors/variables/uninitialized_local_variables.py b/slither/detectors/variables/uninitialized_local_variables.py index 36d9e2bf7..78e76dfcc 100644 --- a/slither/detectors/variables/uninitialized_local_variables.py +++ b/slither/detectors/variables/uninitialized_local_variables.py @@ -76,7 +76,7 @@ Bob calls `transfer`. As a result, the ethers are sent to the address 0x0 and ar self._detect_uninitialized(function, son, visited) - def detect(self): + def _detect(self): """ Detect uninitialized state variables Recursively visit the calls @@ -107,7 +107,6 @@ Bob calls `transfer`. As a result, the ethers are sent to the address 0x0 and ar function.name, uninitialized_local_variable.source_mapping_str) - self.log(info) json = self.generate_json_result(info) self.add_variable_to_json(uninitialized_local_variable, json) diff --git a/slither/detectors/variables/uninitialized_state_variables.py b/slither/detectors/variables/uninitialized_state_variables.py index 35a8bd552..b9dc9ceb3 100644 --- a/slither/detectors/variables/uninitialized_state_variables.py +++ b/slither/detectors/variables/uninitialized_state_variables.py @@ -81,7 +81,7 @@ Initialize all the variables. If a variable is meant to be initialized to zero, not variable.expression and\ variable in read_variables] - def detect(self): + def _detect(self): """ Detect uninitialized state variables Recursively visit the calls @@ -98,7 +98,6 @@ Initialize all the variables. If a variable is meant to be initialized to zero, variable.source_mapping_str) for f in functions: info += "\t- {} ({})\n".format(f.name, f.source_mapping_str) - self.log(info) source = [variable.source_mapping] source += [f.source_mapping for f in functions] diff --git a/slither/detectors/variables/uninitialized_storage_variables.py b/slither/detectors/variables/uninitialized_storage_variables.py index b0d8930d2..914f5c4d6 100644 --- a/slither/detectors/variables/uninitialized_storage_variables.py +++ b/slither/detectors/variables/uninitialized_storage_variables.py @@ -83,7 +83,7 @@ Bob calls `func`. As a result, `owner` is override to 0. self._detect_uninitialized(function, son, visited) - def detect(self): + def _detect(self): """ Detect uninitialized state variables Recursively visit the calls @@ -108,9 +108,6 @@ Bob calls `func`. As a result, `owner` is override to 0. info = "{} in {}.{} ({}) is a storage variable never initialiazed\n" info = info.format(var_name, function.contract.name, function.name, uninitialized_storage_variable.source_mapping_str) - self.log(info) - - json = self.generate_json_result(info) self.add_variable_to_json(uninitialized_storage_variable, json) diff --git a/slither/detectors/variables/unused_state_variables.py b/slither/detectors/variables/unused_state_variables.py index 7705b75ed..c3c716b1b 100644 --- a/slither/detectors/variables/unused_state_variables.py +++ b/slither/detectors/variables/unused_state_variables.py @@ -48,11 +48,10 @@ class UnusedStateVars(AbstractDetector): return [x for x in contract.variables if x not in variables_used and x.visibility != 'public'] - def detect(self): + def _detect(self): """ Detect unused state variables """ results = [] - all_info = '' for c in self.slither.contracts_derived: unusedVars = self.detect_unused(c) if unusedVars: @@ -63,12 +62,9 @@ class UnusedStateVars(AbstractDetector): var.source_mapping_str, c.name) - all_info += info json = self.generate_json_result(info) self.add_variables_to_json(unusedVars, json) results.append(json) - if all_info != '': - self.log(all_info) return results diff --git a/slither/slither.py b/slither/slither.py index 685b1db6f..0963cd0df 100644 --- a/slither/slither.py +++ b/slither/slither.py @@ -60,6 +60,8 @@ class Slither(SlitherSolc): self._analyze_contracts() + self.load_previous_results() + @property def detectors(self): return self._detectors