WIP database

pull/172/head
Josselin 6 years ago
parent 1757618fb4
commit ecebd0414d
  1. 4
      examples/printers/call_graph.sol.dot
  2. 9
      slither/__main__.py
  3. 10
      slither/core/slither_core.py
  4. 29
      slither/detectors/abstract_detector.py
  5. 4
      slither/detectors/all_detectors.py
  6. 4
      slither/detectors/attributes/const_functions.py
  7. 3
      slither/detectors/attributes/constant_pragma.py
  8. 3
      slither/detectors/attributes/incorrect_solc.py
  9. 3
      slither/detectors/attributes/locked_ether.py
  10. 4
      slither/detectors/examples/backdoor.py
  11. 5
      slither/detectors/functions/arbitrary_send.py
  12. 7
      slither/detectors/functions/external_function.py
  13. 4
      slither/detectors/functions/suicidal.py
  14. 15
      slither/detectors/naming_convention/naming_convention.py
  15. 5
      slither/detectors/operations/block_timestamp.py
  16. 8
      slither/detectors/operations/low_level_calls.py
  17. 3
      slither/detectors/operations/unused_return_values.py
  18. 2
      slither/detectors/reentrancy/reentrancy.py
  19. 5
      slither/detectors/reentrancy/reentrancy_benign.py
  20. 5
      slither/detectors/reentrancy/reentrancy_eth.py
  21. 5
      slither/detectors/reentrancy/reentrancy_read_before_write.py
  22. 3
      slither/detectors/shadowing/abstract.py
  23. 4
      slither/detectors/shadowing/builtin_symbols.py
  24. 4
      slither/detectors/shadowing/local.py
  25. 3
      slither/detectors/shadowing/state.py
  26. 7
      slither/detectors/statements/assembly.py
  27. 4
      slither/detectors/statements/calls_in_loop.py
  28. 3
      slither/detectors/statements/controlled_delegatecall.py
  29. 5
      slither/detectors/statements/incorrect_strict_equality.py
  30. 4
      slither/detectors/statements/tx_origin.py
  31. 3
      slither/detectors/variables/possible_const_state_variables.py
  32. 3
      slither/detectors/variables/uninitialized_local_variables.py
  33. 3
      slither/detectors/variables/uninitialized_state_variables.py
  34. 5
      slither/detectors/variables/uninitialized_storage_variables.py
  35. 6
      slither/detectors/variables/unused_state_variables.py
  36. 2
      slither/slither.py

@ -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]"

@ -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
###################################################################################

@ -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]

@ -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]

@ -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
#
#

@ -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)

@ -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

@ -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)

@ -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)

@ -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)

@ -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)

@ -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

@ -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)

@ -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

@ -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)

@ -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

@ -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)

@ -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

@ -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:

@ -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:

@ -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 = []

@ -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)

@ -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)

@ -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)

@ -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)

@ -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

@ -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)

@ -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)

@ -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

@ -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)

@ -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

@ -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)

@ -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]

@ -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)

@ -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

@ -60,6 +60,8 @@ class Slither(SlitherSolc):
self._analyze_contracts()
self.load_previous_results()
@property
def detectors(self):
return self._detectors

Loading…
Cancel
Save