Merge pull request #213 from crytic/dev-fix-c3-linearalization

Remove share of functions and modifiers instances
pull/249/head
Feist Josselin 6 years ago committed by GitHub
commit c81c32d31c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      examples/scripts/functions_called.py
  2. 8
      examples/scripts/possible_paths.py
  3. 2
      examples/scripts/slithIR.py
  4. 70
      scripts/tests_generate_expected_json_4.sh
  5. 32
      scripts/tests_generate_expected_json_5.sh
  6. 2
      scripts/travis_install.sh
  7. 1
      scripts/travis_test_4.sh
  8. 2
      scripts/travis_test_5.sh
  9. 17
      scripts/travis_test_upgradability.sh
  10. 1
      slither/core/children/child_contract.py
  11. 13
      slither/core/children/child_inheritance.py
  12. 151
      slither/core/declarations/contract.py
  13. 8
      slither/core/declarations/enum.py
  14. 16
      slither/core/declarations/event.py
  15. 38
      slither/core/declarations/function.py
  16. 10
      slither/core/declarations/structure.py
  17. 5
      slither/core/variables/local_variable.py
  18. 13
      slither/core/variables/state_variable.py
  19. 1
      slither/core/variables/variable.py
  20. 14
      slither/detectors/abstract_detector.py
  21. 13
      slither/detectors/attributes/const_functions.py
  22. 4
      slither/detectors/erc/incorrect_erc20_interface.py
  23. 2
      slither/detectors/erc/incorrect_erc721_interface.py
  24. 8
      slither/detectors/erc/unindexed_event_parameters.py
  25. 7
      slither/detectors/functions/arbitrary_send.py
  26. 5
      slither/detectors/functions/complex_function.py
  27. 9
      slither/detectors/functions/external_function.py
  28. 7
      slither/detectors/functions/suicidal.py
  29. 70
      slither/detectors/naming_convention/naming_convention.py
  30. 7
      slither/detectors/operations/block_timestamp.py
  31. 6
      slither/detectors/operations/low_level_calls.py
  32. 8
      slither/detectors/operations/unused_return_values.py
  33. 2
      slither/detectors/reentrancy/reentrancy.py
  34. 6
      slither/detectors/reentrancy/reentrancy_benign.py
  35. 6
      slither/detectors/reentrancy/reentrancy_eth.py
  36. 6
      slither/detectors/reentrancy/reentrancy_read_before_write.py
  37. 10
      slither/detectors/shadowing/abstract.py
  38. 12
      slither/detectors/shadowing/builtin_symbols.py
  39. 18
      slither/detectors/shadowing/local.py
  40. 10
      slither/detectors/shadowing/state.py
  41. 6
      slither/detectors/statements/assembly.py
  42. 7
      slither/detectors/statements/calls_in_loop.py
  43. 2
      slither/detectors/statements/controlled_delegatecall.py
  44. 10
      slither/detectors/statements/deprecated_calls.py
  45. 4
      slither/detectors/statements/incorrect_strict_equality.py
  46. 4
      slither/detectors/statements/tx_origin.py
  47. 4
      slither/detectors/variables/possible_const_state_variables.py
  48. 7
      slither/detectors/variables/uninitialized_local_variables.py
  49. 5
      slither/detectors/variables/uninitialized_state_variables.py
  50. 4
      slither/detectors/variables/uninitialized_storage_variables.py
  51. 4
      slither/detectors/variables/unused_state_variables.py
  52. 18
      slither/printers/inheritance/inheritance_graph.py
  53. 2
      slither/printers/summary/data_depenency.py
  54. 6
      slither/printers/summary/slithir.py
  55. 6
      slither/printers/summary/slithir_ssa.py
  56. 37
      slither/slithir/convert.py
  57. 22
      slither/slithir/operations/internal_call.py
  58. 2
      slither/slithir/utils/ssa.py
  59. 87
      slither/solc_parsing/declarations/contract.py
  60. 3
      slither/solc_parsing/declarations/function.py
  61. 55
      slither/solc_parsing/expressions/expression_parsing.py
  62. 6
      slither/solc_parsing/solidity_types/type_parsing.py
  63. 9
      slither/utils/inheritance_analysis.py
  64. 2
      slither/visitors/slithir/expression_to_slithir.py
  65. 4
      tests/check-upgradeability/test_5.txt
  66. 4
      tests/expected_json/arbitrary_send-0.5.1.arbitrary-send.json
  67. 4
      tests/expected_json/arbitrary_send-0.5.1.arbitrary-send.txt
  68. 4
      tests/expected_json/arbitrary_send.arbitrary-send.json
  69. 4
      tests/expected_json/arbitrary_send.arbitrary-send.txt
  70. 2
      tests/expected_json/backdoor.suicidal.json
  71. 2
      tests/expected_json/backdoor.suicidal.txt
  72. 2
      tests/expected_json/constant-0.5.1.constant-function.json
  73. 2
      tests/expected_json/constant-0.5.1.constant-function.txt
  74. 6
      tests/expected_json/constant.constant-function.json
  75. 6
      tests/expected_json/constant.constant-function.txt
  76. 8
      tests/expected_json/external_function.external-function.json
  77. 8
      tests/expected_json/external_function.external-function.txt
  78. 24
      tests/expected_json/incorrect_equality.incorrect-equality.json
  79. 24
      tests/expected_json/incorrect_equality.incorrect-equality.txt
  80. 12
      tests/expected_json/incorrect_erc20_interface.erc20-interface.json
  81. 12
      tests/expected_json/incorrect_erc20_interface.erc20-interface.txt
  82. 20
      tests/expected_json/incorrect_erc721_interface.erc721-interface.json
  83. 20
      tests/expected_json/incorrect_erc721_interface.erc721-interface.txt
  84. 2
      tests/expected_json/inline_assembly_contract-0.5.1.assembly.json
  85. 2
      tests/expected_json/inline_assembly_contract-0.5.1.assembly.txt
  86. 2
      tests/expected_json/inline_assembly_contract.assembly.json
  87. 2
      tests/expected_json/inline_assembly_contract.assembly.txt
  88. 4
      tests/expected_json/inline_assembly_library-0.5.1.assembly.json
  89. 4
      tests/expected_json/inline_assembly_library-0.5.1.assembly.txt
  90. 4
      tests/expected_json/inline_assembly_library.assembly.json
  91. 4
      tests/expected_json/inline_assembly_library.assembly.txt
  92. 2
      tests/expected_json/low_level_calls.low-level-calls.json
  93. 2
      tests/expected_json/low_level_calls.low-level-calls.txt
  94. 2
      tests/expected_json/multiple_calls_in_loop.calls-loop.json
  95. 2
      tests/expected_json/multiple_calls_in_loop.calls-loop.txt
  96. 10
      tests/expected_json/naming_convention.naming-convention.json
  97. 10
      tests/expected_json/naming_convention.naming-convention.txt
  98. 2
      tests/expected_json/old_solc.sol.json.solc-version.txt
  99. 4
      tests/expected_json/reentrancy-0.5.1.reentrancy-eth.json
  100. 4
      tests/expected_json/reentrancy-0.5.1.reentrancy-eth.txt
  101. Some files were not shown because too many files have changed in this diff Show More

@ -16,7 +16,7 @@ entry_point = contract.get_function_from_signature('entry_point()')
all_calls = entry_point.all_internal_calls() all_calls = entry_point.all_internal_calls()
all_calls_formated = [f.contract.name + '.' + f.name for f in all_calls] all_calls_formated = [f.canonical_name for f in all_calls]
# Print the result # Print the result
print('From entry_point the functions reached are {}'.format(all_calls_formated)) print('From entry_point the functions reached are {}'.format(all_calls_formated))

@ -69,7 +69,7 @@ def all_function_definitions(function):
:return: Returns a list composed of the provided function definition and any base definitions. :return: Returns a list composed of the provided function definition and any base definitions.
""" """
return [function] + [f for c in function.contract.inheritance return [function] + [f for c in function.contract.inheritance
for f in c.functions_and_modifiers_not_inherited for f in c.functions_and_modifiers_declared
if f.full_name == function.full_name] if f.full_name == function.full_name]
@ -86,7 +86,7 @@ def __find_target_paths(target_function, current_path=[]):
# Look through all functions # Look through all functions
for contract in slither.contracts: for contract in slither.contracts:
for function in contract.functions_and_modifiers_not_inherited: for function in contract.functions_and_modifiers_declared:
# If the function is already in our path, skip it. # If the function is already in our path, skip it.
if function in current_path: if function in current_path:
@ -179,12 +179,12 @@ reaching_functions = set([y for x in reaching_paths for y in x if y not in targe
# Print out all function names which can reach the targets. # Print out all function names which can reach the targets.
print(f"The following functions reach the specified targets:") print(f"The following functions reach the specified targets:")
for function_desc in sorted([f"{f.contract.name}.{f.full_name}" for f in reaching_functions]): for function_desc in sorted([f"{f.canonical_name}" for f in reaching_functions]):
print(f"-{function_desc}") print(f"-{function_desc}")
print("\n") print("\n")
# Format all function paths. # Format all function paths.
reaching_paths_str = [' -> '.join([f"{f.contract.name}.{f.full_name}" for f in reaching_path]) for reaching_path in reaching_paths] reaching_paths_str = [' -> '.join([f"{f.canonical_name}" for f in reaching_path]) for reaching_path in reaching_paths]
# Print a sorted list of all function paths which can reach the targets. # Print a sorted list of all function paths which can reach the targets.
print(f"The following paths reach the specified targets:") print(f"The following paths reach the specified targets:")

@ -15,7 +15,7 @@ for contract in slither.contracts:
for function in contract.functions: for function in contract.functions:
# Dont explore inherited functions # Dont explore inherited functions
if function.contract == contract: if function.contract_declarer == contract:
print('Function: {}'.format(function.name)) print('Function: {}'.format(function.name))

@ -21,38 +21,38 @@ generate_expected_json(){
} }
#generate_expected_json tests/deprecated_calls.sol "deprecated-standards" generate_expected_json tests/deprecated_calls.sol "deprecated-standards"
#generate_expected_json tests/erc20_indexed.sol "erc20-indexed" generate_expected_json tests/erc20_indexed.sol "erc20-indexed"
#generate_expected_json tests/incorrect_erc20_interface.sol "erc20-interface" generate_expected_json tests/incorrect_erc20_interface.sol "erc20-interface"
#generate_expected_json tests/incorrect_erc721_interface.sol "erc721-interface" generate_expected_json tests/incorrect_erc721_interface.sol "erc721-interface"
#generate_expected_json tests/uninitialized.sol "uninitialized-state" generate_expected_json tests/uninitialized.sol "uninitialized-state"
#generate_expected_json tests/backdoor.sol "backdoor" generate_expected_json tests/backdoor.sol "backdoor"
#generate_expected_json tests/backdoor.sol "suicidal" generate_expected_json tests/backdoor.sol "suicidal"
#generate_expected_json tests/pragma.0.4.24.sol "pragma" generate_expected_json tests/pragma.0.4.24.sol "pragma"
#generate_expected_json tests/old_solc.sol.json "solc-version" generate_expected_json tests/old_solc.sol.json "solc-version"
#generate_expected_json tests/reentrancy.sol "reentrancy-eth" generate_expected_json tests/reentrancy.sol "reentrancy-eth"
#generate_expected_json tests/uninitialized_storage_pointer.sol "uninitialized-storage" generate_expected_json tests/uninitialized_storage_pointer.sol "uninitialized-storage"
#generate_expected_json tests/tx_origin.sol "tx-origin" generate_expected_json tests/tx_origin.sol "tx-origin"
#generate_expected_json tests/unused_state.sol "unused-state" generate_expected_json tests/unused_state.sol "unused-state"
#generate_expected_json tests/locked_ether.sol "locked-ether" generate_expected_json tests/locked_ether.sol "locked-ether"
#generate_expected_json tests/arbitrary_send.sol "arbitrary-send" generate_expected_json tests/arbitrary_send.sol "arbitrary-send"
#generate_expected_json tests/inline_assembly_contract.sol "assembly" generate_expected_json tests/inline_assembly_contract.sol "assembly"
#generate_expected_json tests/inline_assembly_library.sol "assembly" generate_expected_json tests/inline_assembly_library.sol "assembly"
#generate_expected_json tests/low_level_calls.sol "low-level-calls" generate_expected_json tests/low_level_calls.sol "low-level-calls"
#generate_expected_json tests/const_state_variables.sol "constable-states" generate_expected_json tests/const_state_variables.sol "constable-states"
#generate_expected_json tests/external_function.sol "external-function" generate_expected_json tests/external_function.sol "external-function"
#generate_expected_json tests/external_function_2.sol "external-function" generate_expected_json tests/external_function_2.sol "external-function"
#generate_expected_json tests/naming_convention.sol "naming-convention" generate_expected_json tests/naming_convention.sol "naming-convention"
#generate_expected_json tests/uninitialized_local_variable.sol "uninitialized-local" generate_expected_json tests/uninitialized_local_variable.sol "uninitialized-local"
#generate_expected_json tests/controlled_delegatecall.sol "controlled-delegatecall" generate_expected_json tests/controlled_delegatecall.sol "controlled-delegatecall"
#generate_expected_json tests/constant.sol "constant-function" generate_expected_json tests/constant.sol "constant-function"
#generate_expected_json tests/unused_return.sol "unused-return" generate_expected_json tests/unused_return.sol "unused-return"
#generate_expected_json tests/shadowing_state_variable.sol "shadowing-state" generate_expected_json tests/shadowing_state_variable.sol "shadowing-state"
#generate_expected_json tests/shadowing_abstract.sol "shadowing-abstract" generate_expected_json tests/shadowing_abstract.sol "shadowing-abstract"
#generate_expected_json tests/timestamp.sol "timestamp" generate_expected_json tests/timestamp.sol "timestamp"
#generate_expected_json tests/multiple_calls_in_loop.sol "calls-loop" generate_expected_json tests/multiple_calls_in_loop.sol "calls-loop"
#generate_expected_json tests/shadowing_builtin_symbols.sol "shadowing-builtin" generate_expected_json tests/shadowing_builtin_symbols.sol "shadowing-builtin"
#generate_expected_json tests/shadowing_local_variable.sol "shadowing-local" generate_expected_json tests/shadowing_local_variable.sol "shadowing-local"
#generate_expected_json tests/solc_version_incorrect.sol "solc-version" generate_expected_json tests/solc_version_incorrect.sol "solc-version"
#generate_expected_json tests/right_to_left_override.sol "rtlo" generate_expected_json tests/right_to_left_override.sol "rtlo"
#generate_expected_json tests/unchecked_lowlevel.sol "unchecked-lowlevel" generate_expected_json tests/unchecked_lowlevel.sol "unchecked-lowlevel"

@ -20,20 +20,20 @@ generate_expected_json(){
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$output_filename_txt" -i sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$output_filename_txt" -i
} }
#generate_expected_json tests/solc_version_incorrect_05.ast.json "solc-version" generate_expected_json tests/solc_version_incorrect_05.ast.json "solc-version"
#generate_expected_json tests/uninitialized-0.5.1.sol "uninitialized-state" generate_expected_json tests/uninitialized-0.5.1.sol "uninitialized-state"
#generate_expected_json tests/backdoor.sol "backdoor" generate_expected_json tests/backdoor.sol "backdoor"
#generate_expected_json tests/backdoor.sol "suicidal" generate_expected_json tests/backdoor.sol "suicidal"
#generate_expected_json tests/old_solc.sol.json "solc-version" generate_expected_json tests/old_solc.sol.json "solc-version"
#generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy-eth" generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy-eth"
#generate_expected_json tests/tx_origin-0.5.1.sol "tx-origin" generate_expected_json tests/tx_origin-0.5.1.sol "tx-origin"
#generate_expected_json tests/locked_ether-0.5.1.sol "locked-ether" generate_expected_json tests/locked_ether-0.5.1.sol "locked-ether"
#generate_expected_json tests/arbitrary_send-0.5.1.sol "arbitrary-send" generate_expected_json tests/arbitrary_send-0.5.1.sol "arbitrary-send"
#generate_expected_json tests/inline_assembly_contract-0.5.1.sol "assembly" generate_expected_json tests/inline_assembly_contract-0.5.1.sol "assembly"
#generate_expected_json tests/inline_assembly_library-0.5.1.sol "assembly" generate_expected_json tests/inline_assembly_library-0.5.1.sol "assembly"
#generate_expected_json tests/constant-0.5.1.sol "constant-function" generate_expected_json tests/constant-0.5.1.sol "constant-function"
#generate_expected_json tests/incorrect_equality.sol "incorrect-equality" generate_expected_json tests/incorrect_equality.sol "incorrect-equality"
#generate_expected_json tests/too_many_digits.sol "too-many-digits" generate_expected_json tests/too_many_digits.sol "too-many-digits"
#generate_expected_json tests/unchecked_lowlevel-0.5.1.sol "unchecked-lowlevel" generate_expected_json tests/unchecked_lowlevel-0.5.1.sol "unchecked-lowlevel"
#generate_expected_json tests/unchecked_send-0.5.1.sol "unchecked-send" generate_expected_json tests/unchecked_send-0.5.1.sol "unchecked-send"

@ -24,5 +24,3 @@ function install_solc {
install_solc install_solc

@ -94,6 +94,7 @@ test_slither tests/external_function_2.sol "external-function"
test_slither tests/naming_convention.sol "naming-convention" test_slither tests/naming_convention.sol "naming-convention"
#test_slither tests/complex_func.sol "complex-function" #test_slither tests/complex_func.sol "complex-function"
test_slither tests/controlled_delegatecall.sol "controlled-delegatecall" test_slither tests/controlled_delegatecall.sol "controlled-delegatecall"
test_slither tests/uninitialized_local_variable.sol "uninitialized-local"
test_slither tests/constant.sol "constant-function" test_slither tests/constant.sol "constant-function"
test_slither tests/unused_return.sol "unused-return" test_slither tests/unused_return.sol "unused-return"
test_slither tests/shadowing_abstract.sol "shadowing-abstract" test_slither tests/shadowing_abstract.sol "shadowing-abstract"

@ -88,7 +88,7 @@ test_slither tests/const_state_variables.sol "constable-states"
test_slither tests/external_function.sol "external-function" test_slither tests/external_function.sol "external-function"
test_slither tests/external_function_2.sol "external-function" test_slither tests/external_function_2.sol "external-function"
test_slither tests/naming_convention.sol "naming-convention" test_slither tests/naming_convention.sol "naming-convention"
##test_slither tests/complex_func.sol "complex-function" #test_slither tests/complex_func.sol "complex-function"
test_slither tests/controlled_delegatecall.sol "controlled-delegatecall" test_slither tests/controlled_delegatecall.sol "controlled-delegatecall"
test_slither tests/constant-0.5.1.sol "constant-function" test_slither tests/constant-0.5.1.sol "constant-function"
test_slither tests/unused_return.sol "unused-return" test_slither tests/unused_return.sol "unused-return"

@ -8,8 +8,9 @@ slither-check-upgradeability "$DIR_TESTS/proxy.sol" Proxy "$DIR_TESTS/contractV1
DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt") DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
echo "slither-check-upgradeability failed" echo "slither-check-upgradeability 1 failed"
cat test_1.txt cat test_1.txt
echo ""
cat "$DIR_TESTS/test_1.txt" cat "$DIR_TESTS/test_1.txt"
exit -1 exit -1
fi fi
@ -18,8 +19,9 @@ slither-check-upgradeability "$DIR_TESTS/proxy.sol" Proxy "$DIR_TESTS/contractV1
DIFF=$(diff test_2.txt "$DIR_TESTS/test_2.txt") DIFF=$(diff test_2.txt "$DIR_TESTS/test_2.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
echo "slither-check-upgradeability failed" echo "slither-check-upgradeability 2 failed"
cat test_2.txt cat test_2.txt
echo ""
cat "$DIR_TESTS/test_2.txt" cat "$DIR_TESTS/test_2.txt"
exit -1 exit -1
fi fi
@ -28,8 +30,9 @@ slither-check-upgradeability "$DIR_TESTS/proxy.sol" Proxy "$DIR_TESTS/contractV1
DIFF=$(diff test_3.txt "$DIR_TESTS/test_3.txt") DIFF=$(diff test_3.txt "$DIR_TESTS/test_3.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
echo "slither-check-upgradeability failed" echo "slither-check-upgradeability 3 failed"
cat test_3.txt cat test_3.txt
echo ""
cat "$DIR_TESTS/test_3.txt" cat "$DIR_TESTS/test_3.txt"
exit -1 exit -1
fi fi
@ -38,8 +41,9 @@ slither-check-upgradeability "$DIR_TESTS/proxy.sol" Proxy "$DIR_TESTS/contractV1
DIFF=$(diff test_4.txt "$DIR_TESTS/test_4.txt") DIFF=$(diff test_4.txt "$DIR_TESTS/test_4.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
echo "slither-check-upgradeability failed" echo "slither-check-upgradeability 4 failed"
cat test_4.txt cat test_4.txt
echo ""
cat "$DIR_TESTS/test_4.txt" cat "$DIR_TESTS/test_4.txt"
exit -1 exit -1
fi fi
@ -48,9 +52,12 @@ slither-check-upgradeability "$DIR_TESTS/proxy.sol" Proxy "$DIR_TESTS/contract_i
DIFF=$(diff test_5.txt "$DIR_TESTS/test_5.txt") DIFF=$(diff test_5.txt "$DIR_TESTS/test_5.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
echo "slither-check-upgradeability failed" echo "slither-check-upgradeability 5 failed"
cat test_5.txt cat test_5.txt
echo ""
cat "$DIR_TESTS/test_5.txt" cat "$DIR_TESTS/test_5.txt"
echo ""
echo "$DIFF"
exit -1 exit -1
fi fi

@ -11,3 +11,4 @@ class ChildContract:
@property @property
def contract(self): def contract(self):
return self._contract return self._contract

@ -0,0 +1,13 @@
class ChildInheritance:
def __init__(self):
super(ChildInheritance, self).__init__()
self._contract_declarer = None
def set_contract_declarer(self, contract):
self._contract_declarer = contract
@property
def contract_declarer(self):
return self._contract_declarer

@ -35,6 +35,7 @@ class Contract(ChildSlither, SourceMapping):
self._variables = {} self._variables = {}
self._modifiers = {} self._modifiers = {}
self._functions = {} self._functions = {}
self._using_for = {} self._using_for = {}
self._kind = None self._kind = None
@ -77,6 +78,20 @@ class Contract(ChildSlither, SourceMapping):
''' '''
return list(self._structures.values()) return list(self._structures.values())
@property
def structures_inherited(self):
'''
list(Structure): List of the inherited structures
'''
return [s for s in self.structures if s.contract != self]
@property
def structures_declared(self):
'''
list(Structues): List of the structures declared within the contract (not inherited)
'''
return [s for s in self.structures if s.contract == self]
def structures_as_dict(self): def structures_as_dict(self):
return self._structures return self._structures
@ -91,6 +106,20 @@ class Contract(ChildSlither, SourceMapping):
def enums(self): def enums(self):
return list(self._enums.values()) return list(self._enums.values())
@property
def enums_inherited(self):
'''
list(Enum): List of the inherited enums
'''
return [e for e in self.enums if e.contract != self]
@property
def enums_declared(self):
'''
list(Enum): List of the enums declared within the contract (not inherited)
'''
return [e for e in self.enums if e.contract == self]
def enums_as_dict(self): def enums_as_dict(self):
return self._enums return self._enums
@ -108,6 +137,20 @@ class Contract(ChildSlither, SourceMapping):
''' '''
return list(self._events.values()) return list(self._events.values())
@property
def events_inherited(self):
'''
list(Event): List of the inherited events
'''
return [e for e in self.events if e.contract != self]
@property
def events_declared(self):
'''
list(Event): List of the events declared within the contract (not inherited)
'''
return [e for e in self.events if e.contract == self]
def events_as_dict(self): def events_as_dict(self):
return self._events return self._events
@ -153,6 +196,20 @@ class Contract(ChildSlither, SourceMapping):
''' '''
return list(self._variables.values()) return list(self._variables.values())
@property
def state_variables_inherited(self):
'''
list(StateVariable): List of the inherited state variables
'''
return [s for s in self.state_variables if s.contract != self]
@property
def state_variables_declared(self):
'''
list(StateVariable): List of the state variables declared within the contract (not inherited)
'''
return [s for s in self.state_variables if s.contract == self]
@property @property
def slithir_variables(self): def slithir_variables(self):
''' '''
@ -177,18 +234,18 @@ class Contract(ChildSlither, SourceMapping):
executed, following the c3 linearization executed, following the c3 linearization
Return None if there is no constructor. Return None if there is no constructor.
''' '''
cst = self.constructor_not_inherited cst = self.constructors_declared
if cst: if cst:
return cst return cst
for inherited_contract in self.inheritance: for inherited_contract in self.inheritance:
cst = inherited_contract.constructor_not_inherited cst = inherited_contract.constructors_declared
if cst: if cst:
return cst return cst
return None return None
@property @property
def constructor_not_inherited(self): def constructors_declared(self):
return next((func for func in self.functions if func.is_constructor and func.contract == self), None) return next((func for func in self.functions if func.is_constructor and func.contract_declarer == self), None)
@property @property
def constructors(self): def constructors(self):
@ -238,29 +295,29 @@ class Contract(ChildSlither, SourceMapping):
''' '''
return list(self._functions.values()) return list(self._functions.values())
def functions_as_dict(self): def available_functions_as_dict(self):
return self._functions return {f.full_name: f for f in self._functions.values() if not f.is_shadowed}
@property @property
def functions_inherited(self): def functions_inherited(self):
''' '''
list(Function): List of the inherited functions list(Function): List of the inherited functions
''' '''
return [f for f in self.functions if f.contract != self] return [f for f in self.functions if f.contract_declarer != self]
@property @property
def functions_not_inherited(self): def functions_declared(self):
''' '''
list(Function): List of the functions defined within the contract (not inherited) list(Function): List of the functions defined within the contract (not inherited)
''' '''
return [f for f in self.functions if f.contract == self] return [f for f in self.functions if f.contract_declarer == self]
@property @property
def functions_entry_points(self): def functions_entry_points(self):
''' '''
list(Functions): List of public and external functions list(Functions): List of public and external functions
''' '''
return [f for f in self.functions if f.visibility in ['public', 'external']] return [f for f in self.functions if f.visibility in ['public', 'external'] and not f.is_shadowed]
@property @property
def modifiers(self): def modifiers(self):
@ -269,22 +326,22 @@ class Contract(ChildSlither, SourceMapping):
''' '''
return list(self._modifiers.values()) return list(self._modifiers.values())
def modifiers_as_dict(self): def available_modifiers_as_dict(self):
return self._modifiers return {m.full_name: m for m in self._modifiers.values() if not m.is_shadowed}
@property @property
def modifiers_inherited(self): def modifiers_inherited(self):
''' '''
list(Modifier): List of the inherited modifiers list(Modifier): List of the inherited modifiers
''' '''
return [m for m in self.modifiers if m.contract != self] return [m for m in self.modifiers if m.contract_declarer != self]
@property @property
def modifiers_not_inherited(self): def modifiers_declared(self):
''' '''
list(Modifier): List of the modifiers defined within the contract (not inherited) list(Modifier): List of the modifiers defined within the contract (not inherited)
''' '''
return [m for m in self.modifiers if m.contract == self] return [m for m in self.modifiers if m.contract_declarer == self]
@property @property
def functions_and_modifiers(self): def functions_and_modifiers(self):
@ -301,11 +358,36 @@ class Contract(ChildSlither, SourceMapping):
return self.functions_inherited + self.modifiers_inherited return self.functions_inherited + self.modifiers_inherited
@property @property
def functions_and_modifiers_not_inherited(self): def functions_and_modifiers_declared(self):
''' '''
list(Function|Modifier): List of the functions and modifiers defined within the contract (not inherited) list(Function|Modifier): List of the functions and modifiers defined within the contract (not inherited)
''' '''
return self.functions_not_inherited + self.modifiers_not_inherited return self.functions_declared + self.modifiers_declared
def available_elements_from_inheritances(self, elements, getter_available):
"""
:param elements: dict(canonical_name -> elements)
:param getter_available: fun x
:return:
"""
# keep track of the contracts visited
# to prevent an ovveride due to multiple inheritance of the same contract
# A is B, C, D is C, --> the second C was already seen
inherited_elements = {}
accessible_elements = {}
contracts_visited = []
for father in self.inheritance_reverse:
functions = {v.full_name: v for (_, v) in getter_available(father)
if not v.contract in contracts_visited}
contracts_visited.append(father)
inherited_elements.update(functions)
for element in inherited_elements.values():
accessible_elements[element.full_name] = elements[element.canonical_name]
return accessible_elements
# endregion # endregion
################################################################################### ###################################################################################
@ -375,7 +457,7 @@ class Contract(ChildSlither, SourceMapping):
Returns: Returns:
Function Function
""" """
return next((f for f in self.functions if f.full_name == function_signature), None) return next((f for f in self.functions if f.full_name == function_signature and not f.is_shadowed), None)
def get_modifier_from_signature(self, modifier_signature): def get_modifier_from_signature(self, modifier_signature):
""" """
@ -385,7 +467,28 @@ class Contract(ChildSlither, SourceMapping):
Returns: Returns:
Modifier Modifier
""" """
return next((m for m in self.modifiers if m.full_name == modifier_signature), None) return next((m for m in self.modifiers if m.full_name == modifier_signature and not m.is_shadowed), None)
def get_function_from_canonical_name(self, canonical_name):
"""
Return a function from a a canonical name (contract.signature())
Args:
canonical_name (str): canonical name of the function (without return statement)
Returns:
Function
"""
return next((f for f in self.functions if f.canonical_name == canonical_name), None)
def get_modifier_from_canonical_name(self, canonical_name):
"""
Return a modifier from a canonical name (contract.signature())
Args:
canonical_name (str): canonical name of the modifier
Returns:
Modifier
"""
return next((m for m in self.modifiers if m.canonical_name == canonical_name), None)
def get_state_variable_from_name(self, variable_name): def get_state_variable_from_name(self, variable_name):
""" """
@ -456,7 +559,7 @@ class Contract(ChildSlither, SourceMapping):
list(core.Function) list(core.Function)
''' '''
candidates = [c.functions_not_inherited for c in self.inheritance] candidates = [c.functions_declared for c in self.inheritance]
candidates = [candidate for sublist in candidates for candidate in sublist] candidates = [candidate for sublist in candidates for candidate in sublist]
return [f for f in candidates if f.full_name == function.full_name] return [f for f in candidates if f.full_name == function.full_name]
@ -470,10 +573,12 @@ class Contract(ChildSlither, SourceMapping):
@property @property
def all_functions_called(self): def all_functions_called(self):
''' '''
list(Function): List of functions reachable from the contract (include super) list(Function): List of functions reachable from the contract
Includes super, and private/internal functions not shadowed
''' '''
all_calls = [f.all_internal_calls() for f in self.functions + self.modifiers] + [self.functions + self.modifiers] all_calls = [f for f in self.functions + self.modifiers if not f.is_shadowed]
all_calls = [item for sublist in all_calls for item in sublist] + self.functions all_calls = [f.all_internal_calls() for f in all_calls] + [all_calls]
all_calls = [item for sublist in all_calls for item in sublist]
all_calls = list(set(all_calls)) all_calls = list(set(all_calls))
all_constructors = [c.constructor for c in self.inheritance] all_constructors = [c.constructor for c in self.inheritance]

@ -19,5 +19,13 @@ class Enum(ChildContract, SourceMapping):
def values(self): def values(self):
return self._values return self._values
def is_declared_by(self, contract):
"""
Check if the element is declared by the contract
:param contract:
:return:
"""
return self.contract == contract
def __str__(self): def __str__(self):
return self.name return self.name

@ -29,9 +29,25 @@ class Event(ChildContract, SourceMapping):
name, parameters = self.signature name, parameters = self.signature
return name+'('+','.join(parameters)+')' return name+'('+','.join(parameters)+')'
@property
def canonical_name(self):
''' Return the function signature as a str
Returns:
str: contract.func_name(type1,type2)
'''
return self.contract.name + self.full_name
@property @property
def elems(self): def elems(self):
return self._elems return self._elems
def is_declared_by(self, contract):
"""
Check if the element is declared by the contract
:param contract:
:return:
"""
return self.contract == contract
def __str__(self): def __str__(self):
return self.name return self.name

@ -6,6 +6,7 @@ from collections import namedtuple
from itertools import groupby from itertools import groupby
from slither.core.children.child_contract import ChildContract from slither.core.children.child_contract import ChildContract
from slither.core.children.child_inheritance import ChildInheritance
from slither.core.declarations.solidity_variables import (SolidityFunction, from slither.core.declarations.solidity_variables import (SolidityFunction,
SolidityVariable, SolidityVariable,
SolidityVariableComposed) SolidityVariableComposed)
@ -18,7 +19,7 @@ logger = logging.getLogger("Function")
ReacheableNode = namedtuple('ReacheableNode', ['node', 'ir']) ReacheableNode = namedtuple('ReacheableNode', ['node', 'ir'])
class Function(ChildContract, SourceMapping): class Function(ChildContract, ChildInheritance, SourceMapping):
""" """
Function class Function class
""" """
@ -84,6 +85,8 @@ class Function(ChildContract, SourceMapping):
self._all_conditional_solidity_variables_read_with_loop = None self._all_conditional_solidity_variables_read_with_loop = None
self._all_solidity_variables_used_as_args = None self._all_solidity_variables_used_as_args = None
self._is_shadowed = False
# set(ReacheableNode) # set(ReacheableNode)
self._reachable_from_nodes = set() self._reachable_from_nodes = set()
self._reachable_from_functions = set() self._reachable_from_functions = set()
@ -116,12 +119,21 @@ class Function(ChildContract, SourceMapping):
name, parameters, _ = self.signature name, parameters, _ = self.signature
return name+'('+','.join(parameters)+')' return name+'('+','.join(parameters)+')'
@property
def canonical_name(self):
"""
str: contract.func_name(type1,type2)
Return the function signature without the return values
"""
name, parameters, _ = self.signature
return self.contract_declarer.name + '.' + name + '(' + ','.join(parameters) + ')'
@property @property
def is_constructor(self): def is_constructor(self):
""" """
bool: True if the function is the constructor bool: True if the function is the constructor
""" """
return self._is_constructor or self._name == self.contract.name return self._is_constructor or self._name == self.contract_declarer.name
@property @property
def contains_assembly(self): def contains_assembly(self):
@ -131,6 +143,14 @@ class Function(ChildContract, SourceMapping):
def slither(self): def slither(self):
return self.contract.slither return self.contract.slither
def is_declared_by(self, contract):
"""
Check if the element is declared by the contract
:param contract:
:return:
"""
return self.contract_declarer == contract
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################
@ -173,6 +193,14 @@ class Function(ChildContract, SourceMapping):
""" """
return self._pure return self._pure
@property
def is_shadowed(self):
return self._is_shadowed
@is_shadowed.setter
def is_shadowed(self, is_shadowed):
self._is_shadowed = is_shadowed
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################
@ -307,7 +335,7 @@ class Function(ChildContract, SourceMapping):
included. included.
""" """
# This is a list of contracts internally, so we convert it to a list of constructor functions. # This is a list of contracts internally, so we convert it to a list of constructor functions.
return [c.constructor_not_inherited for c in self._explicit_base_constructor_calls if c.constructor_not_inherited] return [c.constructors_declared for c in self._explicit_base_constructor_calls if c.constructors_declared]
# endregion # endregion
@ -560,7 +588,7 @@ class Function(ChildContract, SourceMapping):
list(core.Function) list(core.Function)
''' '''
candidates = [c.functions_not_inherited for c in self.contract.inheritance] candidates = [c.functions_declared for c in self.contract.inheritance]
candidates = [candidate for sublist in candidates for candidate in sublist] candidates = [candidate for sublist in candidates for candidate in sublist]
return [f for f in candidates if f.full_name == self.full_name] return [f for f in candidates if f.full_name == self.full_name]
@ -933,7 +961,7 @@ class Function(ChildContract, SourceMapping):
(str, str, str, list(str), list(str), listr(str), list(str), list(str); (str, str, str, list(str), list(str), listr(str), list(str), list(str);
contract_name, name, visibility, modifiers, vars read, vars written, internal_calls, external_calls_as_expressions contract_name, name, visibility, modifiers, vars read, vars written, internal_calls, external_calls_as_expressions
""" """
return (self.contract.name, self.full_name, self.visibility, return (self.contract_declarer.name, self.full_name, self.visibility,
[str(x) for x in self.modifiers], [str(x) for x in self.modifiers],
[str(x) for x in self.state_variables_read + self.solidity_variables_read], [str(x) for x in self.state_variables_read + self.solidity_variables_read],
[str(x) for x in self.state_variables_written], [str(x) for x in self.state_variables_written],

@ -25,6 +25,15 @@ class Structure(ChildContract, SourceMapping):
def elems(self): def elems(self):
return self._elems return self._elems
def is_declared_by(self, contract):
"""
Check if the element is declared by the contract
:param contract:
:return:
"""
return self.contract == contract
@property @property
def elems_ordered(self): def elems_ordered(self):
ret = [] ret = []
@ -32,5 +41,6 @@ class Structure(ChildContract, SourceMapping):
ret.append(self._elems[e]) ret.append(self._elems[e])
return ret return ret
def __str__(self): def __str__(self):
return self.name return self.name

@ -50,3 +50,8 @@ class LocalVariable(ChildFunction, Variable):
return False return False
@property
def canonical_name(self):
return self.name

@ -4,6 +4,16 @@ from slither.utils.type import export_nested_types_from_variable
class StateVariable(ChildContract, Variable): class StateVariable(ChildContract, Variable):
def is_declared_by(self, contract):
"""
Check if the element is declared by the contract
:param contract:
:return:
"""
return self.contract == contract
################################################################################### ###################################################################################
################################################################################### ###################################################################################
# region Signature # region Signature
@ -36,7 +46,7 @@ class StateVariable(ChildContract, Variable):
@property @property
def canonical_name(self): def canonical_name(self):
return '{}:{}'.format(self.contract.name, self.name) return '{}.{}'.format(self.contract.name, self.name)
@property @property
def full_name(self): def full_name(self):
@ -51,3 +61,4 @@ class StateVariable(ChildContract, Variable):
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################

@ -78,6 +78,7 @@ class Variable(SourceMapping):
assert isinstance(t, (Type, list)) or t is None assert isinstance(t, (Type, list)) or t is None
self._type = t self._type = t
def __str__(self): def __str__(self):
return self._name return self._name

@ -160,7 +160,13 @@ class AbstractDetector(metaclass=abc.ABCMeta):
def _create_parent_element(element): def _create_parent_element(element):
from slither.core.children.child_contract import ChildContract from slither.core.children.child_contract import ChildContract
from slither.core.children.child_function import ChildFunction from slither.core.children.child_function import ChildFunction
if isinstance(element, ChildContract): from slither.core.children.child_inheritance import ChildInheritance
if isinstance(element, ChildInheritance):
if element.contract_declarer:
contract = {'elements': []}
AbstractDetector.add_contract_to_json(element.contract_declarer, contract)
return contract['elements'][0]
elif isinstance(element, ChildContract):
if element.contract: if element.contract:
contract = {'elements': []} contract = {'elements': []}
AbstractDetector.add_contract_to_json(element.contract, contract) AbstractDetector.add_contract_to_json(element.contract, contract)
@ -211,10 +217,11 @@ class AbstractDetector(metaclass=abc.ABCMeta):
additional_fields) additional_fields)
d['elements'].append(element) d['elements'].append(element)
@staticmethod @staticmethod
def add_functions_to_json(functions, d): def add_functions_to_json(functions, d, additional_fields={}):
for function in sorted(functions, key=lambda x: x.name): for function in sorted(functions, key=lambda x: x.name):
AbstractDetector.add_function_to_json(function, d) AbstractDetector.add_function_to_json(function, d, additional_fields)
@staticmethod @staticmethod
def add_enum_to_json(enum, d, additional_fields={}): def add_enum_to_json(enum, d, additional_fields={}):
@ -267,6 +274,7 @@ class AbstractDetector(metaclass=abc.ABCMeta):
additional_fields) additional_fields)
d['elements'].append(element) d['elements'].append(element)
@staticmethod @staticmethod
def add_nodes_to_json(nodes, d): def add_nodes_to_json(nodes, d):
for node in sorted(nodes, key=lambda x: x.node_id): for node in sorted(nodes, key=lambda x: x.node_id):

@ -51,13 +51,13 @@ All the calls to `get` revert, breaking Bob's smart contract execution.'''
results = [] results = []
for c in self.contracts: for c in self.contracts:
for f in c.functions: for f in c.functions:
if f.contract != c: if f.contract_declarer != c:
continue continue
if f.view or f.pure: if f.view or f.pure:
if f.contains_assembly: if f.contains_assembly:
attr = 'view' if f.view else 'pure' attr = 'view' if f.view else 'pure'
info = '{}.{} ({}) is declared {} but contains assembly code\n' info = '{} ({}) is declared {} but contains assembly code\n'
info = info.format(f.contract.name, f.name, f.source_mapping_str, attr) info = info.format(f.canonical_name, f.source_mapping_str, attr)
json = self.generate_json_result(info, {'contains_assembly': True}) json = self.generate_json_result(info, {'contains_assembly': True})
self.add_function_to_json(f, json) self.add_function_to_json(f, json)
results.append(json) results.append(json)
@ -65,11 +65,10 @@ All the calls to `get` revert, breaking Bob's smart contract execution.'''
variables_written = f.all_state_variables_written() variables_written = f.all_state_variables_written()
if variables_written: if variables_written:
attr = 'view' if f.view else 'pure' attr = 'view' if f.view else 'pure'
info = '{}.{} ({}) is declared {} but changes state variables:\n' info = '{} ({}) is declared {} but changes state variables:\n'
info = info.format(f.contract.name, f.name, f.source_mapping_str, attr) info = info.format(f.canonical_name, f.source_mapping_str, attr)
for variable_written in variables_written: for variable_written in variables_written:
info += '\t- {}.{}\n'.format(variable_written.contract.name, info += '\t- {}\n'.format(variable_written.canonical_name)
variable_written.name)
json = self.generate_json_result(info, {'contains_assembly': False}) json = self.generate_json_result(info, {'contains_assembly': False})
self.add_function_to_json(f, json) self.add_function_to_json(f, json)

@ -61,6 +61,7 @@ contract Token{
Returns: Returns:
list(str) : list of incorrect function signatures list(str) : list of incorrect function signatures
""" """
# Verify this is an ERC20 contract. # Verify this is an ERC20 contract.
if not contract.is_possible_erc20(): if not contract.is_possible_erc20():
return [] return []
@ -72,6 +73,7 @@ contract Token{
funcs = contract.functions funcs = contract.functions
functions = [f for f in funcs if IncorrectERC20InterfaceDetection.incorrect_erc20_interface(f.signature)] functions = [f for f in funcs if IncorrectERC20InterfaceDetection.incorrect_erc20_interface(f.signature)]
return functions return functions
def _detect(self): def _detect(self):
@ -87,7 +89,7 @@ contract Token{
for function in functions: for function in functions:
info = "{} ({}) has incorrect ERC20 function interface: {} ({})\n".format(c.name, info = "{} ({}) has incorrect ERC20 function interface: {} ({})\n".format(c.name,
c.source_mapping_str, c.source_mapping_str,
function.name, function.full_name,
function.source_mapping_str) function.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
self.add_function_to_json(function, json) self.add_function_to_json(function, json)

@ -88,7 +88,7 @@ contract Token{
for function in functions: for function in functions:
info = "{} ({}) has incorrect ERC721 function interface: {} ({})\n".format(c.name, info = "{} ({}) has incorrect ERC721 function interface: {} ({})\n".format(c.name,
c.source_mapping_str, c.source_mapping_str,
function.name, function.full_name,
function.source_mapping_str) function.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
self.add_function_to_json(function, json) self.add_function_to_json(function, json)

@ -47,11 +47,7 @@ In this case, Transfer and Approval events should have the 'indexed' keyword on
return results return results
# Loop through all events to look for poor form. # Loop through all events to look for poor form.
for event in contract.events: for event in contract.events_declared:
# Only handle events which are declared in this contract.
if event.contract != contract:
continue
# If this is transfer/approval events, expect the first two parameters to be indexed. # If this is transfer/approval events, expect the first two parameters to be indexed.
if event.full_name in ["Transfer(address,address,uint256)", if event.full_name in ["Transfer(address,address,uint256)",
@ -74,6 +70,7 @@ In this case, Transfer and Approval events should have the 'indexed' keyword on
if unindexed_params: if unindexed_params:
# Add each problematic event definition to our result list # Add each problematic event definition to our result list
for (event, parameter) in unindexed_params: for (event, parameter) in unindexed_params:
info = "ERC20 event {}.{} ({}) does not index parameter '{}'\n".format(c.name, event.name, event.source_mapping_str, parameter.name) info = "ERC20 event {}.{} ({}) does not index parameter '{}'\n".format(c.name, event.name, event.source_mapping_str, parameter.name)
# Add the events to the JSON (note: we do not add the params/vars as they have no source mapping). # Add the events to the JSON (note: we do not add the params/vars as they have no source mapping).
@ -83,4 +80,5 @@ In this case, Transfer and Approval events should have the 'indexed' keyword on
}) })
results.append(json) results.append(json)
return results return results

@ -94,7 +94,7 @@ Bob calls `setDestination` and `withdraw`. As a result he withdraws the contract
list((Function), (list (Node))) list((Function), (list (Node)))
""" """
ret = [] ret = []
for f in [f for f in contract.functions if f.contract == contract]: for f in [f for f in contract.functions if f.contract_declarer == contract]:
nodes = self.arbitrary_send(f) nodes = self.arbitrary_send(f)
if nodes: if nodes:
ret.append((f, nodes)) ret.append((f, nodes))
@ -109,9 +109,8 @@ Bob calls `setDestination` and `withdraw`. As a result he withdraws the contract
arbitrary_send = self.detect_arbitrary_send(c) arbitrary_send = self.detect_arbitrary_send(c)
for (func, nodes) in arbitrary_send: for (func, nodes) in arbitrary_send:
info = "{}.{} ({}) sends eth to arbitrary user\n" info = "{} ({}) sends eth to arbitrary user\n"
info = info.format(func.contract.name, info = info.format(func.canonical_name,
func.name,
func.source_mapping_str) func.source_mapping_str)
info += '\tDangerous calls:\n' info += '\tDangerous calls:\n'
for node in nodes: for node in nodes:

@ -90,7 +90,7 @@ class ComplexFunction(AbstractDetector):
for issue in issues: for issue in issues:
func, cause = issue.values() func, cause = issue.values()
txt = "{}.{} ({}) is a complex function:\n" txt = "{} ({}) is a complex function:\n"
if cause == self.CAUSE_EXTERNAL_CALL: if cause == self.CAUSE_EXTERNAL_CALL:
txt += "\t- Reason: High number of external calls" txt += "\t- Reason: High number of external calls"
@ -99,8 +99,7 @@ class ComplexFunction(AbstractDetector):
if cause == self.CAUSE_STATE_VARS: if cause == self.CAUSE_STATE_VARS:
txt += "\t- Reason: High number of modified state variables" txt += "\t- Reason: High number of modified state variables"
info = txt.format(func.contract.name, info = txt.format(func.canonical_name,
func.name,
func.source_mapping_str) func.source_mapping_str)
info = info + "\n" info = info + "\n"
self.log(info) self.log(info)

@ -71,7 +71,7 @@ class ExternalFunction(AbstractDetector):
for contract in function.contract.inheritance + [function.contract]: for contract in function.contract.inheritance + [function.contract]:
# Loop through the functions not inherited (explicitly defined in this contract). # Loop through the functions not inherited (explicitly defined in this contract).
for f in contract.functions_not_inherited: for f in contract.functions_declared:
# If it matches names, this is the base most function. # If it matches names, this is the base most function.
if f.full_name == function.full_name: if f.full_name == function.full_name:
@ -120,7 +120,7 @@ class ExternalFunction(AbstractDetector):
continue continue
# Next we'll want to loop through all functions defined directly in this contract. # Next we'll want to loop through all functions defined directly in this contract.
for function in contract.functions_not_inherited: for function in contract.functions_declared:
# If the function is a constructor, or is public, we skip it. # If the function is a constructor, or is public, we skip it.
if function.is_constructor or function.visibility != "public": if function.is_constructor or function.visibility != "public":
@ -165,9 +165,8 @@ class ExternalFunction(AbstractDetector):
# Loop for each function definition, and recommend it be declared external. # Loop for each function definition, and recommend it be declared external.
for function_definition in all_function_definitions: for function_definition in all_function_definitions:
txt = "{}.{} ({}) should be declared external\n" txt = "{} ({}) should be declared external\n"
info = txt.format(function_definition.contract.name, info = txt.format(function_definition.canonical_name,
function_definition.name,
function_definition.source_mapping_str) function_definition.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)

@ -59,7 +59,7 @@ Bob calls `kill` and destructs the contract.'''
def detect_suicidal(self, contract): def detect_suicidal(self, contract):
ret = [] ret = []
for f in [f for f in contract.functions if f.contract == contract]: for f in [f for f in contract.functions if f.contract_declarer == contract]:
if self.detect_suicidal_func(f): if self.detect_suicidal_func(f):
ret.append(f) ret.append(f)
return ret return ret
@ -72,9 +72,8 @@ Bob calls `kill` and destructs the contract.'''
functions = self.detect_suicidal(c) functions = self.detect_suicidal(c)
for func in functions: for func in functions:
txt = "{}.{} ({}) allows anyone to destruct the contract\n" txt = "{} ({}) allows anyone to destruct the contract\n"
info = txt.format(func.contract.name, info = txt.format(func.canonical_name,
func.name,
func.source_mapping_str) func.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)

@ -67,13 +67,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
}) })
results.append(json) results.append(json)
for struct in contract.structures: for struct in contract.structures_declared:
if struct.contract != contract:
continue
if not self.is_cap_words(struct.name): if not self.is_cap_words(struct.name):
info = "Struct '{}.{}' ({}) is not in CapWords\n" info = "Struct '{}' ({}) is not in CapWords\n"
info = info.format(struct.contract.name, struct.name, struct.source_mapping_str) info = info.format(struct.canonical_name, struct.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
self.add_struct_to_json(struct, json, { self.add_struct_to_json(struct, json, {
@ -82,13 +79,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
}) })
results.append(json) results.append(json)
for event in contract.events: for event in contract.events_declared:
if event.contract != contract:
continue
if not self.is_cap_words(event.name): if not self.is_cap_words(event.name):
info = "Event '{}.{}' ({}) is not in CapWords\n" info = "Event '{}' ({}) is not in CapWords\n"
info = info.format(event.contract.name, event.name, event.source_mapping_str) info = info.format(event.canonical_name, event.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
self.add_event_to_json(event, json, { self.add_event_to_json(event, json, {
@ -97,13 +91,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
}) })
results.append(json) results.append(json)
for func in contract.functions: for func in contract.functions_declared:
if func.contract != contract:
continue
if not self.is_mixed_case(func.name): if not self.is_mixed_case(func.name):
info = "Function '{}.{}' ({}) is not in mixedCase\n" info = "Function '{}' ({}) is not in mixedCase\n"
info = info.format(func.contract.name, func.name, func.source_mapping_str) info = info.format(func.canonical_name, func.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
self.add_function_to_json(func, json, { self.add_function_to_json(func, json, {
@ -118,10 +109,9 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
else: else:
correct_naming = self.is_mixed_case_with_underscore(argument.name) correct_naming = self.is_mixed_case_with_underscore(argument.name)
if not correct_naming: if not correct_naming:
info = "Parameter '{}' of {}.{} ({}) is not in mixedCase\n" info = "Parameter '{}' of {} ({}) is not in mixedCase\n"
info = info.format(argument.name, info = info.format(argument.name,
argument.function.contract.name, argument.canonical_name,
argument.function,
argument.source_mapping_str) argument.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
@ -131,14 +121,11 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
}) })
results.append(json) results.append(json)
for var in contract.state_variables: for var in contract.state_variables_declared:
if var.contract != contract:
continue
if self.should_avoid_name(var.name): if self.should_avoid_name(var.name):
if not self.is_upper_case_with_underscores(var.name): if not self.is_upper_case_with_underscores(var.name):
info = "Variable '{}.{}' ({}) used l, O, I, which should not be used\n" info = "Variable '{}' ({}) used l, O, I, which should not be used\n"
info = info.format(var.contract.name, var.name, var.source_mapping_str) info = info.format(var.canonical_name, var.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
self.add_variable_to_json(var, json, { self.add_variable_to_json(var, json, {
@ -153,8 +140,8 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
continue continue
if not self.is_upper_case_with_underscores(var.name): if not self.is_upper_case_with_underscores(var.name):
info = "Constant '{}.{}' ({}) is not in UPPER_CASE_WITH_UNDERSCORES\n" info = "Constant '{}' ({}) is not in UPPER_CASE_WITH_UNDERSCORES\n"
info = info.format(var.contract.name, var.name, var.source_mapping_str) info = info.format(var.canonical_name, var.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
self.add_variable_to_json(var, json, { self.add_variable_to_json(var, json, {
@ -169,8 +156,8 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
else: else:
correct_naming = self.is_mixed_case(var.name) correct_naming = self.is_mixed_case(var.name)
if not correct_naming: if not correct_naming:
info = "Variable '{}.{}' ({}) is not in mixedCase\n" info = "Variable '{}' ({}) is not in mixedCase\n"
info = info.format(var.contract.name, var.name, var.source_mapping_str) info = info.format(var.canonical_name, var.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
self.add_variable_to_json(var, json, { self.add_variable_to_json(var, json, {
@ -179,13 +166,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
}) })
results.append(json) results.append(json)
for enum in contract.enums: for enum in contract.enums_declared:
if enum.contract != contract:
continue
if not self.is_cap_words(enum.name): if not self.is_cap_words(enum.name):
info = "Enum '{}.{}' ({}) is not in CapWords\n" info = "Enum '{}' ({}) is not in CapWords\n"
info = info.format(enum.contract.name, enum.name, enum.source_mapping_str) info = info.format(enum.canonical_name, enum.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
self.add_enum_to_json(enum, json, { self.add_enum_to_json(enum, json, {
@ -194,15 +178,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
}) })
results.append(json) results.append(json)
for modifier in contract.modifiers_declared:
for modifier in contract.modifiers:
if modifier.contract != contract:
continue
if not self.is_mixed_case(modifier.name): if not self.is_mixed_case(modifier.name):
info = "Modifier '{}.{}' ({}) is not in mixedCase\n" info = "Modifier '{}' ({}) is not in mixedCase\n"
info = info.format(modifier.contract.name, info = info.format(modifier.canonical_name,
modifier.name,
modifier.source_mapping_str) modifier.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
@ -212,5 +191,4 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
}) })
results.append(json) results.append(json)
return results return results

@ -54,7 +54,7 @@ class Timestamp(AbstractDetector):
list((Function), (list (Node))) list((Function), (list (Node)))
""" """
ret = [] ret = []
for f in [f for f in contract.functions if f.contract == contract]: for f in [f for f in contract.functions if f.contract_declarer == contract]:
nodes = self.timestamp(f) nodes = self.timestamp(f)
if nodes: if nodes:
ret.append((f, nodes)) ret.append((f, nodes))
@ -69,9 +69,8 @@ class Timestamp(AbstractDetector):
dangerous_timestamp = self.detect_dangerous_timestamp(c) dangerous_timestamp = self.detect_dangerous_timestamp(c)
for (func, nodes) in dangerous_timestamp: for (func, nodes) in dangerous_timestamp:
info = "{}.{} ({}) uses timestamp for comparisons\n" info = "{} ({}) uses timestamp for comparisons\n"
info = info.format(func.contract.name, info = info.format(func.canonical_name,
func.name,
func.source_mapping_str) func.source_mapping_str)
info += '\tDangerous comparisons:\n' info += '\tDangerous comparisons:\n'
for node in nodes: for node in nodes:

@ -33,7 +33,7 @@ class LowLevelCalls(AbstractDetector):
def detect_low_level_calls(self, contract): def detect_low_level_calls(self, contract):
ret = [] ret = []
for f in [f for f in contract.functions if contract == f.contract]: for f in [f for f in contract.functions if contract == f.contract_declarer]:
nodes = f.nodes nodes = f.nodes
assembly_nodes = [n for n in nodes if assembly_nodes = [n for n in nodes if
self._contains_low_level_calls(n)] self._contains_low_level_calls(n)]
@ -48,8 +48,8 @@ class LowLevelCalls(AbstractDetector):
for c in self.contracts: for c in self.contracts:
values = self.detect_low_level_calls(c) values = self.detect_low_level_calls(c)
for func, nodes in values: for func, nodes in values:
info = "Low level call in {}.{} ({}):\n" info = "Low level call in {} ({}):\n"
info = info.format(func.contract.name, func.name, func.source_mapping_str) info = info.format(func.canonical_name, func.source_mapping_str)
for node in nodes: for node in nodes:
info += "\t-{} {}\n".format(str(node.expression), node.source_mapping_str) info += "\t-{} {}\n".format(str(node.expression), node.source_mapping_str)

@ -67,14 +67,14 @@ contract MyConc{
results = [] results = []
for c in self.slither.contracts: for c in self.slither.contracts:
for f in c.functions + c.modifiers: for f in c.functions + c.modifiers:
if f.contract != c: if f.contract_declarer != c:
continue continue
unused_return = self.detect_unused_return_values(f) unused_return = self.detect_unused_return_values(f)
if unused_return: if unused_return:
for node in unused_return: for node in unused_return:
info = "{}.{} ({}) ignores return value by {} \"{}\" ({})\n" info = "{} ({}) ignores return value by {} \"{}\" ({})\n"
info = info.format(f.contract.name, info = info.format(f.canonical_name,
f.name,
f.source_mapping_str, f.source_mapping_str,
self._txt_description, self._txt_description,
node.expression, node.expression,

@ -181,7 +181,7 @@ class Reentrancy(AbstractDetector):
def detect_reentrancy(self, contract): def detect_reentrancy(self, contract):
""" """
""" """
for function in contract.functions_and_modifiers_not_inherited: for function in contract.functions_and_modifiers_declared:
if function.is_implemented: if function.is_implemented:
if self.KEY in function.context: if self.KEY in function.context:
continue continue

@ -45,7 +45,7 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
def find_reentrancies(self): def find_reentrancies(self):
result = {} result = {}
for contract in self.contracts: for contract in self.contracts:
for f in contract.functions_and_modifiers_not_inherited: for f in contract.functions_and_modifiers_declared:
for node in f.nodes: for node in f.nodes:
# dead code # dead code
if not self.KEY in node.context: if not self.KEY in node.context:
@ -84,8 +84,8 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
for (func, calls, send_eth), varsWritten in result_sorted: for (func, calls, send_eth), varsWritten in result_sorted:
calls = sorted(list(set(calls)), key=lambda x: x.node_id) calls = sorted(list(set(calls)), key=lambda x: x.node_id)
send_eth = sorted(list(set(send_eth)), key=lambda x: x.node_id) send_eth = sorted(list(set(send_eth)), key=lambda x: x.node_id)
info = 'Reentrancy in {}.{} ({}):\n' info = 'Reentrancy in {} ({}):\n'
info = info.format(func.contract.name, func.name, func.source_mapping_str) info = info.format(func.canonical_name, func.source_mapping_str)
info += '\tExternal calls:\n' info += '\tExternal calls:\n'
for call_info in calls: for call_info in calls:
info += '\t- {} ({})\n'.format(call_info.expression, call_info.source_mapping_str) info += '\t- {} ({})\n'.format(call_info.expression, call_info.source_mapping_str)

@ -47,7 +47,7 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
def find_reentrancies(self): def find_reentrancies(self):
result = {} result = {}
for contract in self.contracts: for contract in self.contracts:
for f in contract.functions_and_modifiers_not_inherited: for f in contract.functions_and_modifiers_declared:
for node in f.nodes: for node in f.nodes:
# dead code # dead code
if not self.KEY in node.context: if not self.KEY in node.context:
@ -87,8 +87,8 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
calls = sorted(list(set(calls)), key=lambda x: x.node_id) calls = sorted(list(set(calls)), key=lambda x: x.node_id)
send_eth = sorted(list(set(send_eth)), key=lambda x: x.node_id) send_eth = sorted(list(set(send_eth)), key=lambda x: x.node_id)
info = 'Reentrancy in {}.{} ({}):\n' info = 'Reentrancy in {} ({}):\n'
info = info.format(func.contract.name, func.name, func.source_mapping_str) info = info.format(func.canonical_name, func.source_mapping_str)
info += '\tExternal calls:\n' info += '\tExternal calls:\n'
for call_info in calls: for call_info in calls:
info += '\t- {} ({})\n'.format(call_info.expression, call_info.source_mapping_str) info += '\t- {} ({})\n'.format(call_info.expression, call_info.source_mapping_str)

@ -46,7 +46,7 @@ Do not report reentrancies that involve ethers (see `reentrancy-eth`)'''
def find_reentrancies(self): def find_reentrancies(self):
result = {} result = {}
for contract in self.contracts: for contract in self.contracts:
for f in contract.functions_and_modifiers_not_inherited: for f in contract.functions_and_modifiers_declared:
for node in f.nodes: for node in f.nodes:
# dead code # dead code
if not self.KEY in node.context: if not self.KEY in node.context:
@ -82,8 +82,8 @@ Do not report reentrancies that involve ethers (see `reentrancy-eth`)'''
result_sorted = sorted(list(reentrancies.items()), key=lambda x:x[0][0].name) result_sorted = sorted(list(reentrancies.items()), key=lambda x:x[0][0].name)
for (func, calls), varsWritten in result_sorted: for (func, calls), varsWritten in result_sorted:
calls = sorted(list(set(calls)), key=lambda x: x.node_id) calls = sorted(list(set(calls)), key=lambda x: x.node_id)
info = 'Reentrancy in {}.{} ({}):\n' info = 'Reentrancy in {} ({}):\n'
info = info.format(func.contract.name, func.name, func.source_mapping_str) info = info.format(func.canonical_name, func.source_mapping_str)
info += '\tExternal calls:\n' info += '\tExternal calls:\n'
for call_info in calls: for call_info in calls:
info += '\t- {} ({})\n'.format(call_info.expression, call_info.source_mapping_str) info += '\t- {} ({})\n'.format(call_info.expression, call_info.source_mapping_str)

@ -41,9 +41,9 @@ contract DerivedContract is BaseContract{
variables_fathers = [] variables_fathers = []
for father in contract.inheritance: for father in contract.inheritance:
if all(not f.is_implemented for f in father.functions + father.modifiers): if all(not f.is_implemented for f in father.functions + father.modifiers):
variables_fathers += [v for v in father.variables if v.contract == father] variables_fathers += father.state_variables_declared
for var in [v for v in contract.variables if v.contract == contract]: for var in contract.state_variables_declared:
shadow = [v for v in variables_fathers if v.name == var.name] shadow = [v for v in variables_fathers if v.name == var.name]
if shadow: if shadow:
ret.append([var] + shadow) ret.append([var] + shadow)
@ -65,12 +65,10 @@ contract DerivedContract is BaseContract{
for all_variables in shadowing: for all_variables in shadowing:
shadow = all_variables[0] shadow = all_variables[0]
variables = all_variables[1:] variables = all_variables[1:]
info = '{}.{} ({}) shadows:\n'.format(shadow.contract.name, info = '{} ({}) shadows:\n'.format(shadow.canonical_name,
shadow.name,
shadow.source_mapping_str) shadow.source_mapping_str)
for var in variables: for var in variables:
info += "\t- {}.{} ({})\n".format(var.contract.name, info += "\t- {} ({})\n".format(var.canonical_name,
var.name,
var.source_mapping_str) var.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)

@ -90,22 +90,18 @@ contract Bug {
result = [] result = []
# Loop through all functions, modifiers, variables (state and local) to detect any built-in symbol keywords. # Loop through all functions, modifiers, variables (state and local) to detect any built-in symbol keywords.
for function in contract.functions: for function in contract.functions_declared:
if function.contract == contract:
if self.is_builtin_symbol(function.name): if self.is_builtin_symbol(function.name):
result.append((self.SHADOWING_FUNCTION, function, None)) result.append((self.SHADOWING_FUNCTION, function, None))
result += self.detect_builtin_shadowing_locals(function) result += self.detect_builtin_shadowing_locals(function)
for modifier in contract.modifiers: for modifier in contract.modifiers_declared:
if modifier.contract == contract:
if self.is_builtin_symbol(modifier.name): if self.is_builtin_symbol(modifier.name):
result.append((self.SHADOWING_MODIFIER, modifier, None)) result.append((self.SHADOWING_MODIFIER, modifier, None))
result += self.detect_builtin_shadowing_locals(modifier) result += self.detect_builtin_shadowing_locals(modifier)
for variable in contract.variables: for variable in contract.state_variables_declared:
if variable.contract == contract:
if self.is_builtin_symbol(variable.name): if self.is_builtin_symbol(variable.name):
result.append((self.SHADOWING_STATE_VARIABLE, variable, None)) result.append((self.SHADOWING_STATE_VARIABLE, variable, None))
for event in contract.events: for event in contract.events_declared:
if event.contract == contract:
if self.is_builtin_symbol(event.name): if self.is_builtin_symbol(event.name):
result.append((self.SHADOWING_EVENT, event, None)) result.append((self.SHADOWING_EVENT, event, None))

@ -58,7 +58,7 @@ contract Bug {
# Loop through all functions + modifiers in this contract. # Loop through all functions + modifiers in this contract.
for function in contract.functions + contract.modifiers: for function in contract.functions + contract.modifiers:
# We should only look for functions declared directly in this contract (not in a base contract). # We should only look for functions declared directly in this contract (not in a base contract).
if function.contract != contract: if function.contract_declarer != contract:
continue continue
# This function was declared in this contract, we check what its local variables might shadow. # This function was declared in this contract, we check what its local variables might shadow.
@ -66,20 +66,20 @@ contract Bug {
overshadowed = [] overshadowed = []
for scope_contract in [contract] + contract.inheritance: for scope_contract in [contract] + contract.inheritance:
# Check functions # Check functions
for scope_function in scope_contract.functions: for scope_function in scope_contract.functions_declared:
if variable.name == scope_function.name and scope_function.contract == scope_contract: if variable.name == scope_function.name:
overshadowed.append((self.OVERSHADOWED_FUNCTION, scope_contract.name, scope_function)) overshadowed.append((self.OVERSHADOWED_FUNCTION, scope_contract.name, scope_function))
# Check modifiers # Check modifiers
for scope_modifier in scope_contract.modifiers: for scope_modifier in scope_contract.modifiers_declared:
if variable.name == scope_modifier.name and scope_modifier.contract == scope_contract: if variable.name == scope_modifier.name:
overshadowed.append((self.OVERSHADOWED_MODIFIER, scope_contract.name, scope_modifier)) overshadowed.append((self.OVERSHADOWED_MODIFIER, scope_contract.name, scope_modifier))
# Check events # Check events
for scope_event in scope_contract.events: for scope_event in scope_contract.events_declared:
if variable.name == scope_event.name and scope_event.contract == scope_contract: if variable.name == scope_event.name:
overshadowed.append((self.OVERSHADOWED_EVENT, scope_contract.name, scope_event)) overshadowed.append((self.OVERSHADOWED_EVENT, scope_contract.name, scope_event))
# Check state variables # Check state variables
for scope_state_variable in scope_contract.variables: for scope_state_variable in scope_contract.state_variables_declared:
if variable.name == scope_state_variable.name and scope_state_variable.contract == scope_contract: if variable.name == scope_state_variable.name:
overshadowed.append((self.OVERSHADOWED_STATE_VARIABLE, scope_contract.name, scope_state_variable)) overshadowed.append((self.OVERSHADOWED_STATE_VARIABLE, scope_contract.name, scope_state_variable))
# If we have found any overshadowed objects, we'll want to add it to our result list. # If we have found any overshadowed objects, we'll want to add it to our result list.

@ -53,9 +53,9 @@ contract DerivedContract is BaseContract{
variables_fathers = [] variables_fathers = []
for father in contract.inheritance: for father in contract.inheritance:
if any(f.is_implemented for f in father.functions + father.modifiers): if any(f.is_implemented for f in father.functions + father.modifiers):
variables_fathers += [v for v in father.variables if v.contract == father] variables_fathers += father.state_variables_declared
for var in [v for v in contract.variables if v.contract == contract]: for var in contract.state_variables_declared:
shadow = [v for v in variables_fathers if v.name == var.name] shadow = [v for v in variables_fathers if v.name == var.name]
if shadow: if shadow:
ret.append([var] + shadow) ret.append([var] + shadow)
@ -76,12 +76,10 @@ contract DerivedContract is BaseContract{
for all_variables in shadowing: for all_variables in shadowing:
shadow = all_variables[0] shadow = all_variables[0]
variables = all_variables[1:] variables = all_variables[1:]
info = '{}.{} ({}) shadows:\n'.format(shadow.contract.name, info = '{} ({}) shadows:\n'.format(shadow.canonical_name,
shadow.name,
shadow.source_mapping_str) shadow.source_mapping_str)
for var in variables: for var in variables:
info += "\t- {}.{} ({})\n".format(var.contract.name, info += "\t- {} ({})\n".format(var.canonical_name,
var.name,
var.source_mapping_str) var.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)

@ -35,7 +35,7 @@ class Assembly(AbstractDetector):
def detect_assembly(self, contract): def detect_assembly(self, contract):
ret = [] ret = []
for f in contract.functions: for f in contract.functions:
if f.contract != contract: if f.contract_declarer != contract:
continue continue
nodes = f.nodes nodes = f.nodes
assembly_nodes = [n for n in nodes if assembly_nodes = [n for n in nodes if
@ -51,8 +51,8 @@ class Assembly(AbstractDetector):
for c in self.contracts: for c in self.contracts:
values = self.detect_assembly(c) values = self.detect_assembly(c)
for func, nodes in values: for func, nodes in values:
info = "{}.{} uses assembly ({})\n" info = "{} uses assembly ({})\n"
info = info.format(func.contract.name, func.name, func.source_mapping_str) info = info.format(func.canonical_name, func.source_mapping_str)
for node in nodes: for node in nodes:
info += "\t- {}\n".format(node.source_mapping_str) info += "\t- {}\n".format(node.source_mapping_str)

@ -72,7 +72,7 @@ If one of the destinations has a fallback function which reverts, `bad` will alw
def detect_call_in_loop(contract): def detect_call_in_loop(contract):
ret = [] ret = []
for f in contract.functions + contract.modifiers: for f in contract.functions + contract.modifiers:
if f.contract == contract and f.is_implemented: if f.contract_declarer == contract and f.is_implemented:
MultipleCallsInLoop.call_in_loop(f.entry_point, MultipleCallsInLoop.call_in_loop(f.entry_point,
False, [], ret) False, [], ret)
@ -86,8 +86,9 @@ If one of the destinations has a fallback function which reverts, `bad` will alw
values = self.detect_call_in_loop(c) values = self.detect_call_in_loop(c)
for node in values: for node in values:
func = node.function func = node.function
info = "{}.{} has external calls inside a loop: \"{}\" ({})\n"
info = info.format(func.contract.name, func.name, node.expression, node.source_mapping_str) info = "{} has external calls inside a loop: \"{}\" ({})\n"
info = info.format(func.canonical_name, node.expression, node.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
self.add_node_to_json(node, json) self.add_node_to_json(node, json)

@ -42,7 +42,7 @@ Bob calls `delegate` and delegates the execution to its malicious contract. As a
for contract in self.slither.contracts: for contract in self.slither.contracts:
for f in contract.functions: for f in contract.functions:
if f.contract != contract: if f.contract_declarer != contract:
continue continue
nodes = self.controlled_delegatecall(f) nodes = self.controlled_delegatecall(f)
if nodes: if nodes:

@ -111,20 +111,14 @@ contract ContractWithDeprecatedReferences {
list of tuple: (state_variable | node, (detecting_signature, original_text, recommended_text))""" list of tuple: (state_variable | node, (detecting_signature, original_text, recommended_text))"""
results = [] results = []
for state_variable in contract.variables: for state_variable in contract.state_variables_declared:
if state_variable.contract != contract:
continue
if state_variable.expression: if state_variable.expression:
deprecated_results = self.detect_deprecation_in_expression(state_variable.expression) deprecated_results = self.detect_deprecation_in_expression(state_variable.expression)
if deprecated_results: if deprecated_results:
results.append((state_variable, deprecated_results)) results.append((state_variable, deprecated_results))
# Loop through all functions + modifiers in this contract. # Loop through all functions + modifiers in this contract.
for function in contract.functions + contract.modifiers: for function in contract.functions_and_modifiers_declared:
# We should only look for functions declared directly in this contract (not in a base contract).
if function.contract != contract:
continue
# Loop through each node in this function. # Loop through each node in this function.
for node in function.nodes: for node in function.nodes:
# Detect deprecated references in the node. # Detect deprecated references in the node.

@ -111,8 +111,8 @@ contract Crowdsale{
# sort ret to get deterministic results # sort ret to get deterministic results
ret = sorted(list(ret.items()), key=lambda x:x[0].name) ret = sorted(list(ret.items()), key=lambda x:x[0].name)
for f, nodes in ret: for f, nodes in ret:
func_info = "{}.{} ({}) uses a dangerous strict equality:\n".format(f.contract.name,
f.name, func_info = "{} ({}) uses a dangerous strict equality:\n".format(f.canonical_name,
f.source_mapping_str) f.source_mapping_str)
# sort the nodes to get deterministic results # sort the nodes to get deterministic results

@ -65,9 +65,9 @@ Bob is the owner of `TxOrigin`. Bob calls Eve's contract. Eve's contract calls `
for c in self.contracts: for c in self.contracts:
values = self.detect_tx_origin(c) values = self.detect_tx_origin(c)
for func, nodes in values: for func, nodes in values:
for node in nodes: for node in nodes:
info = "{}.{} uses tx.origin for authorization: \"{}\" ({})\n".format(func.contract.name, info = "{} uses tx.origin for authorization: \"{}\" ({})\n".format(func.canonical_name,
func.name,
node.expression, node.expression,
node.source_mapping_str) node.source_mapping_str)

@ -86,11 +86,11 @@ class ConstCandidateStateVars(AbstractDetector):
# Create a result for each finding # Create a result for each finding
for v in constable_variables: for v in constable_variables:
info = "{}.{} should be constant ({})\n".format(v.contract.name, info = "{} should be constant ({})\n".format(v.canonical_name,
v.name,
v.source_mapping_str) v.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)
self.add_variable_to_json(v, json) self.add_variable_to_json(v, json)
results.append(json) results.append(json)
return results return results

@ -90,7 +90,7 @@ Bob calls `transfer`. As a result, the ethers are sent to the address 0x0 and ar
for contract in self.slither.contracts: for contract in self.slither.contracts:
for function in contract.functions: for function in contract.functions:
if function.is_implemented and function.contract == contract: if function.is_implemented and function.contract_declarer == contract:
if function.contains_assembly: if function.contains_assembly:
continue continue
# dont consider storage variable, as they are detected by another detector # dont consider storage variable, as they are detected by another detector
@ -101,10 +101,9 @@ Bob calls `transfer`. As a result, the ethers are sent to the address 0x0 and ar
for(function, uninitialized_local_variable) in all_results: for(function, uninitialized_local_variable) in all_results:
var_name = uninitialized_local_variable.name var_name = uninitialized_local_variable.name
info = "{} in {}.{} ({}) is a local variable never initialiazed\n" info = "{} in {} ({}) is a local variable never initialiazed\n"
info = info.format(var_name, info = info.format(var_name,
function.contract.name, function.canonical_name,
function.name,
uninitialized_local_variable.source_mapping_str) uninitialized_local_variable.source_mapping_str)

@ -92,9 +92,8 @@ Initialize all the variables. If a variable is meant to be initialized to zero,
for c in self.slither.contracts_derived: for c in self.slither.contracts_derived:
ret = self.detect_uninitialized(c) ret = self.detect_uninitialized(c)
for variable, functions in ret: for variable, functions in ret:
info = "{}.{} ({}) is never initialized. It is used in:\n" info = "{} ({}) is never initialized. It is used in:\n"
info = info.format(variable.contract.name, info = info.format(variable.canonical_name,
variable.name,
variable.source_mapping_str) variable.source_mapping_str)
for f in functions: for f in functions:
info += "\t- {} ({})\n".format(f.name, f.source_mapping_str) info += "\t- {} ({})\n".format(f.name, f.source_mapping_str)

@ -105,8 +105,8 @@ Bob calls `func`. As a result, `owner` is override to 0.
for(function, uninitialized_storage_variable) in self.results: for(function, uninitialized_storage_variable) in self.results:
var_name = uninitialized_storage_variable.name var_name = uninitialized_storage_variable.name
info = "{} in {}.{} ({}) is a storage variable never initialiazed\n" 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) info = info.format(var_name, function.canonical_name, uninitialized_storage_variable.source_mapping_str)
json = self.generate_json_result(info) json = self.generate_json_result(info)

@ -56,11 +56,11 @@ class UnusedStateVars(AbstractDetector):
unusedVars = self.detect_unused(c) unusedVars = self.detect_unused(c)
if unusedVars: if unusedVars:
for var in unusedVars: for var in unusedVars:
info = "{}.{} ({}) is never used in {}\n".format(var.contract.name, info = "{} ({}) is never used in {}\n".format(var.canonical_name,
var.name,
var.source_mapping_str, var.source_mapping_str,
c.name) c.name)
json = self.generate_json_result(info) json = self.generate_json_result(info)
self.add_variable_to_json(var, json) self.add_variable_to_json(var, json)
self.add_contract_to_json(c, json) self.add_contract_to_json(c, json)

@ -91,8 +91,8 @@ class PrinterInheritanceGraph(AbstractPrinter):
indirect_shadows = detect_c3_function_shadowing(contract) indirect_shadows = detect_c3_function_shadowing(contract)
if indirect_shadows: if indirect_shadows:
for collision_set in sorted(indirect_shadows, key=lambda x: x[0][1].name): for collision_set in sorted(indirect_shadows, key=lambda x: x[0][1].name):
winner = collision_set[-1][1].contract.name winner = collision_set[-1][1].contract_declarer.name
collision_steps = [colliding_function.contract.name for _, colliding_function in collision_set] collision_steps = [colliding_function.contract_declarer.name for _, colliding_function in collision_set]
collision_steps = ', '.join(collision_steps) collision_steps = ', '.join(collision_steps)
result.append(f"'{collision_set[0][1].full_name}' collides in inherited contracts {collision_steps} where {winner} is chosen.") result.append(f"'{collision_set[0][1].full_name}' collides in inherited contracts {collision_steps} where {winner} is chosen.")
return '\n'.join(result) return '\n'.join(result)
@ -116,23 +116,23 @@ class PrinterInheritanceGraph(AbstractPrinter):
# Functions # Functions
visibilities = ['public', 'external'] visibilities = ['public', 'external']
public_functions = [self._get_pattern_func(f, contract) for f in contract.functions if public_functions = [self._get_pattern_func(f, contract) for f in contract.functions if
not f.is_constructor and f.contract == contract and f.visibility in visibilities] not f.is_constructor and f.contract_declarer == contract and f.visibility in visibilities]
public_functions = ''.join(public_functions) public_functions = ''.join(public_functions)
private_functions = [self._get_pattern_func(f, contract) for f in contract.functions if private_functions = [self._get_pattern_func(f, contract) for f in contract.functions if
not f.is_constructor and f.contract == contract and f.visibility not in visibilities] not f.is_constructor and f.contract_declarer == contract and f.visibility not in visibilities]
private_functions = ''.join(private_functions) private_functions = ''.join(private_functions)
# Modifiers # Modifiers
modifiers = [self._get_pattern_func(m, contract) for m in contract.modifiers if m.contract == contract] modifiers = [self._get_pattern_func(m, contract) for m in contract.modifiers if m.contract_declarer == contract]
modifiers = ''.join(modifiers) modifiers = ''.join(modifiers)
# Public variables # Public variables
public_variables = [self._get_pattern_var(v, contract) for v in contract.variables if public_variables = [self._get_pattern_var(v, contract) for v in contract.state_variables_declared
v.contract == contract and v.visibility in visibilities] if v.visibility in visibilities]
public_variables = ''.join(public_variables) public_variables = ''.join(public_variables)
private_variables = [self._get_pattern_var(v, contract) for v in contract.variables if private_variables = [self._get_pattern_var(v, contract) for v in contract.state_variables_declared
v.contract == contract and v.visibility not in visibilities] if v.visibility not in visibilities]
private_variables = ''.join(private_variables) private_variables = ''.join(private_variables)
# Obtain any indirect shadowing information for this node. # Obtain any indirect shadowing information for this node.

@ -35,7 +35,7 @@ class DataDependency(AbstractPrinter):
txt += str(table) txt += str(table)
txt += "\n" txt += "\n"
for f in c.functions_and_modifiers_not_inherited: for f in c.functions_and_modifiers_declared:
txt += "\nFunction %s\n"%f.full_name txt += "\nFunction %s\n"%f.full_name
table = PrettyTable(['Variable', 'Dependencies']) table = PrettyTable(['Variable', 'Dependencies'])
for v in f.variables: for v in f.variables:

@ -23,8 +23,7 @@ class PrinterSlithIR(AbstractPrinter):
for contract in self.contracts: for contract in self.contracts:
print('Contract {}'.format(contract.name)) print('Contract {}'.format(contract.name))
for function in contract.functions: for function in contract.functions:
if function.contract == contract: print(f'\tFunction {function.canonical_name}')
print('\tFunction {}'.format(function.full_name))
for node in function.nodes: for node in function.nodes:
if node.expression: if node.expression:
print('\t\tExpression: {}'.format(node.expression)) print('\t\tExpression: {}'.format(node.expression))
@ -36,8 +35,7 @@ class PrinterSlithIR(AbstractPrinter):
for ir in node.irs: for ir in node.irs:
print('\t\t\t{}'.format(ir)) print('\t\t\t{}'.format(ir))
for modifier in contract.modifiers: for modifier in contract.modifiers:
if modifier.contract == contract: print('\tModifier {}'.format(modifier.canonical_name))
print('\tModifier {}'.format(modifier.full_name))
for node in modifier.nodes: for node in modifier.nodes:
print(node) print(node)
if node.expression: if node.expression:

@ -23,8 +23,7 @@ class PrinterSlithIRSSA(AbstractPrinter):
for contract in self.contracts: for contract in self.contracts:
print('Contract {}'.format(contract.name)) print('Contract {}'.format(contract.name))
for function in contract.functions: for function in contract.functions:
if function.contract == contract: print('\tFunction {}'.format(function.canonical_name))
print('\tFunction {}'.format(function.full_name))
for node in function.nodes: for node in function.nodes:
if node.expression: if node.expression:
print('\t\tExpression: {}'.format(node.expression)) print('\t\tExpression: {}'.format(node.expression))
@ -33,8 +32,7 @@ class PrinterSlithIRSSA(AbstractPrinter):
for ir in node.irs_ssa: for ir in node.irs_ssa:
print('\t\t\t{}'.format(ir)) print('\t\t\t{}'.format(ir))
for modifier in contract.modifiers: for modifier in contract.modifiers:
if modifier.contract == contract: print('\tModifier {}'.format(modifier.canonical_name))
print('\tModifier {}'.format(modifier.full_name))
for node in modifier.nodes: for node in modifier.nodes:
print(node) print(node)
if node.expression: if node.expression:

@ -104,6 +104,21 @@ def get_sig(ir, name):
argss = convert_arguments(ir.arguments) argss = convert_arguments(ir.arguments)
return [sig.format(name, ','.join(args)) for args in argss] return [sig.format(name, ','.join(args)) for args in argss]
def get_canonical_names(ir, function_name, contract_name):
'''
Return a list of potential signature
It is a list, as Constant variables can be converted to int256
Args:
ir (slithIR.operation)
Returns:
list(str)
'''
sig = '{}({})'
# list of list of arguments
argss = convert_arguments(ir.arguments)
return [sig.format(f'{contract_name}.{function_name}', ','.join(args)) for args in argss]
def convert_arguments(arguments): def convert_arguments(arguments):
argss = [[]] argss = [[]]
for arg in arguments: for arg in arguments:
@ -399,7 +414,7 @@ def propagate_types(ir, node):
elif isinstance(ir, InternalCall): elif isinstance(ir, InternalCall):
# if its not a tuple, return a singleton # if its not a tuple, return a singleton
if ir.function is None: if ir.function is None:
convert_type_of_high_and_internal_level_call(ir, ir.contract) convert_type_of_high_and_internal_level_call(ir, node.function.contract)
return_type = ir.function.return_type return_type = ir.function.return_type
if return_type: if return_type:
if len(return_type) == 1: if len(return_type) == 1:
@ -520,7 +535,7 @@ def extract_tmp_call(ins, contract):
# If there is a call on an inherited contract, it is an internal call or an event # If there is a call on an inherited contract, it is an internal call or an event
if ins.ori.variable_left in contract.inheritance + [contract]: if ins.ori.variable_left in contract.inheritance + [contract]:
if str(ins.ori.variable_right) in [f.name for f in contract.functions]: if str(ins.ori.variable_right) in [f.name for f in contract.functions]:
internalcall = InternalCall(ins.ori.variable_right, ins.ori.variable_left, ins.nbr_arguments, ins.lvalue, ins.type_call) internalcall = InternalCall((ins.ori.variable_right, ins.ori.variable_left.name), ins.nbr_arguments, ins.lvalue, ins.type_call)
internalcall.call_id = ins.call_id internalcall.call_id = ins.call_id
return internalcall return internalcall
if str(ins.ori.variable_right) in [f.name for f in contract.events]: if str(ins.ori.variable_right) in [f.name for f in contract.events]:
@ -695,7 +710,10 @@ def look_for_library(contract, ir, node, using_for, t):
return None return None
def convert_to_library(ir, node, using_for): def convert_to_library(ir, node, using_for):
contract = node.function.contract # We use contract_declarer, because Solidity resolve the library
# before resolving the inheritance.
# Though we could use .contract as libraries cannot be shadowed
contract = node.function.contract_declarer
t = ir.destination.type t = ir.destination.type
if t in using_for: if t in using_for:
@ -759,9 +777,20 @@ def convert_type_library_call(ir, lib_contract):
def convert_type_of_high_and_internal_level_call(ir, contract): def convert_type_of_high_and_internal_level_call(ir, contract):
func = None func = None
if isinstance(ir, InternalCall):
sigs = get_canonical_names(ir, ir.function_name, ir.contract_name)
for sig in sigs:
func = contract.get_function_from_canonical_name(sig)
if not func:
func = contract.get_state_variable_from_name(ir.function_name)
if func:
# stop to explore if func is found (prevent dupplicate issue)
break
else:
assert isinstance(ir, HighLevelCall)
sigs = get_sig(ir, ir.function_name) sigs = get_sig(ir, ir.function_name)
for sig in sigs: for sig in sigs:
func = contract.get_function_from_signature(sig) func = contract.get_function_from_canonical_name(sig)
if not func: if not func:
func = contract.get_state_variable_from_name(ir.function_name) func = contract.get_state_variable_from_name(ir.function_name)
if func: if func:

@ -1,21 +1,20 @@
from slither.core.declarations.function import Function from slither.core.declarations.function import Function
from slither.slithir.operations.call import Call from slither.slithir.operations.call import Call
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.core.variables.variable import Variable
from slither.slithir.variables import Constant from slither.slithir.variables import Constant
class InternalCall(Call, OperationWithLValue): class InternalCall(Call, OperationWithLValue):
def __init__(self, function, contract, nbr_arguments, result, type_call): def __init__(self, function, nbr_arguments, result, type_call):
super(InternalCall, self).__init__() super(InternalCall, self).__init__()
if isinstance(function, Function): if isinstance(function, Function):
self._function = function self._function = function
self._function_name = function.name self._function_name = function.name
self._contract_name = function.contract_declarer.name
else: else:
isinstance(function, Constant)
self._function = None self._function = None
self._function_name = function self._function_name, self._contract_name = function
self._contract = contract #self._contract = contract
self._nbr_arguments = nbr_arguments self._nbr_arguments = nbr_arguments
self._type_call = type_call self._type_call = type_call
self._lvalue = result self._lvalue = result
@ -32,14 +31,14 @@ class InternalCall(Call, OperationWithLValue):
def function(self, f): def function(self, f):
self._function = f self._function = f
@property
def contract(self):
return self._contract
@property @property
def function_name(self): def function_name(self):
return self._function_name return self._function_name
@property
def contract_name(self):
return self._contract_name
@property @property
def nbr_arguments(self): def nbr_arguments(self):
return self._nbr_arguments return self._nbr_arguments
@ -56,9 +55,8 @@ class InternalCall(Call, OperationWithLValue):
lvalue = '{}({}) = '.format(self.lvalue, ','.join(str(x) for x in self.lvalue.type)) lvalue = '{}({}) = '.format(self.lvalue, ','.join(str(x) for x in self.lvalue.type))
else: else:
lvalue = '{}({}) = '.format(self.lvalue, self.lvalue.type) lvalue = '{}({}) = '.format(self.lvalue, self.lvalue.type)
txt = '{}INTERNAL_CALL, {}.{}({})' txt = '{}INTERNAL_CALL, {}({})'
return txt.format(lvalue, return txt.format(lvalue,
self.function.contract.name, self.function.canonical_name,
self.function.full_name,
','.join(args)) ','.join(args))

@ -566,7 +566,7 @@ def copy_ir(ir, *instances):
nbr_arguments = ir.nbr_arguments nbr_arguments = ir.nbr_arguments
lvalue = get_variable(ir, lambda x: x.lvalue, *instances) lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
type_call = ir.type_call type_call = ir.type_call
new_ir = InternalCall(function, function.contract, nbr_arguments, lvalue, type_call) new_ir = InternalCall(function, nbr_arguments, lvalue, type_call)
new_ir.arguments = get_arguments(ir, *instances) new_ir.arguments = get_arguments(ir, *instances)
return new_ir return new_ir
elif isinstance(ir, InternalDynamicCall): elif isinstance(ir, InternalDynamicCall):

@ -232,8 +232,9 @@ class ContractSolc04(Contract):
def _parse_modifier(self, modifier): def _parse_modifier(self, modifier):
modif = ModifierSolc(modifier, self) modif = ModifierSolc(modifier, self, self)
modif.set_contract(self) modif.set_contract(self)
modif.set_contract_declarer(self)
modif.set_offset(modifier['src'], self.slither) modif.set_offset(modifier['src'], self.slither)
self.slither.add_modifier(modif) self.slither.add_modifier(modif)
self._modifiers_no_params.append(modif) self._modifiers_no_params.append(modif)
@ -247,7 +248,7 @@ class ContractSolc04(Contract):
return return
def _parse_function(self, function): def _parse_function(self, function):
func = FunctionSolc(function, self) func = FunctionSolc(function, self, self)
func.set_offset(function['src'], self.slither) func.set_offset(function['src'], self.slither)
self.slither.add_function(func) self.slither.add_function(func)
self._functions_no_params.append(func) self._functions_no_params.append(func)
@ -281,26 +282,52 @@ class ContractSolc04(Contract):
return return
def analyze_params_modifiers(self): def analyze_params_modifiers(self):
for father in self.inheritance_reverse:
self._modifiers.update(father.modifiers_as_dict())
for modifier in self._modifiers_no_params: elements_no_params = self._modifiers_no_params
modifier.analyze_params() getter = lambda f: f.modifiers
self._modifiers[modifier.full_name] = modifier getter_available = lambda f: f.available_modifiers_as_dict().items()
Cls = ModifierSolc
self._modifiers = self._analyze_params_elements(elements_no_params, getter, getter_available, Cls)
self._modifiers_no_params = [] self._modifiers_no_params = []
return return
def analyze_params_functions(self): def analyze_params_functions(self):
# keep track of the contracts visited
# to prevent an ovveride due to multiple inheritance of the same contract elements_no_params = self._functions_no_params
# A is B, C, D is C, --> the second C was already seen getter = lambda f: f.functions
contracts_visited = [] getter_available = lambda f: f.available_functions_as_dict().items()
for father in self.inheritance_reverse: Cls = FunctionSolc
functions = {k:v for (k, v) in father.functions_as_dict().items() self._functions = self._analyze_params_elements(elements_no_params, getter, getter_available, Cls)
if not v.contract in contracts_visited}
contracts_visited.append(father) self._functions_no_params = []
self._functions.update(functions) return
def _analyze_params_elements(self, elements_no_params, getter, getter_available, Cls):
"""
Analyze the parameters of the given elements (Function or Modifier).
The function iterates over the inheritance to create an instance or inherited elements (Function or Modifier)
If the element is shadowed, set is_shadowed to True
:param elements_no_params: list of elements to analyzer
:param getter: fun x
:param getter_available: fun x
:param Cls: Class to create for collision
:return:
"""
all_elements = {}
accessible_elements = {}
for father in self.inheritance:
for element in getter(father):
elem = Cls(element._functionNotParsed, self, element.contract_declarer)
elem.set_offset(element._functionNotParsed['src'], self.slither)
elem.analyze_params()
self.slither.add_function(elem)
all_elements[elem.canonical_name] = elem
accessible_elements = self.available_elements_from_inheritances(all_elements, getter_available)
# If there is a constructor in the functions # If there is a constructor in the functions
# We remove the previous constructor # We remove the previous constructor
@ -308,20 +335,25 @@ class ContractSolc04(Contract):
# #
# Note: contract.all_functions_called returns the constructors of the base contracts # Note: contract.all_functions_called returns the constructors of the base contracts
has_constructor = False has_constructor = False
for function in self._functions_no_params: for element in elements_no_params:
function.analyze_params() element.analyze_params()
if function.is_constructor: if element.is_constructor:
has_constructor = True has_constructor = True
if has_constructor: if has_constructor:
_functions = {k:v for (k, v) in self._functions.items() if not v.is_constructor} _accessible_functions = {k: v for (k, v) in accessible_elements.items() if not v.is_constructor}
self._functions = _functions
for element in elements_no_params:
accessible_elements[element.full_name] = element
all_elements[element.canonical_name] = element
for element in all_elements.values():
if accessible_elements[element.full_name] != all_elements[element.canonical_name]:
element.is_shadowed = True
return all_elements
for function in self._functions_no_params:
self._functions[function.full_name] = function
self._functions_no_params = []
return
def analyze_constant_state_variables(self): def analyze_constant_state_variables(self):
from slither.solc_parsing.expressions.expression_parsing import VariableNotFound from slither.solc_parsing.expressions.expression_parsing import VariableNotFound
@ -434,14 +466,12 @@ class ContractSolc04(Contract):
def convert_expression_to_slithir(self): def convert_expression_to_slithir(self):
for func in self.functions + self.modifiers: for func in self.functions + self.modifiers:
if func.contract == self:
func.generate_slithir_and_analyze() func.generate_slithir_and_analyze()
all_ssa_state_variables_instances = dict() all_ssa_state_variables_instances = dict()
for contract in self.inheritance: for contract in self.inheritance:
for v in contract.variables: for v in contract.state_variables_declared:
if v.contract == contract:
new_var = StateIRVariable(v) new_var = StateIRVariable(v)
all_ssa_state_variables_instances[v.canonical_name] = new_var all_ssa_state_variables_instances[v.canonical_name] = new_var
self._initial_state_variables.append(new_var) self._initial_state_variables.append(new_var)
@ -453,7 +483,6 @@ class ContractSolc04(Contract):
self._initial_state_variables.append(new_var) self._initial_state_variables.append(new_var)
for func in self.functions + self.modifiers: for func in self.functions + self.modifiers:
if func.contract == self:
func.generate_slithir_ssa(all_ssa_state_variables_instances) func.generate_slithir_ssa(all_ssa_state_variables_instances)
def fix_phi(self): def fix_phi(self):

@ -36,9 +36,10 @@ class FunctionSolc(Function):
""" """
# elems = [(type, name)] # elems = [(type, name)]
def __init__(self, function, contract): def __init__(self, function, contract, contract_declarer):
super(FunctionSolc, self).__init__() super(FunctionSolc, self).__init__()
self._contract = contract self._contract = contract
self._contract_declarer = contract_declarer
# Only present if compact AST # Only present if compact AST
self._referenced_declaration = None self._referenced_declaration = None

@ -60,15 +60,31 @@ def get_pointer_name(variable):
return None return None
def find_variable(var_name, caller_context, referenced_declaration=None): def find_variable(var_name, caller_context, referenced_declaration=None, is_super=False):
# variable are looked from the contract declarer
# functions can be shadowed, but are looked from the contract instance, rather than the contract declarer
# the difference between function and variable come from the fact that an internal call, or an variable access
# in a function does not behave similariy, for example in:
# contract C{
# function f(){
# state_var = 1
# f2()
# }
# state_var will refer to C.state_var, no mater if C is inherited
# while f2() will refer to the function definition of the inherited contract (C.f2() in the context of C, or
# the contract inheriting from C)
# for events it's unclear what should be the behavior, as they can be shadowed, but there is not impact
# structure/enums cannot be shadowed
if isinstance(caller_context, Contract): if isinstance(caller_context, Contract):
function = None function = None
contract = caller_context contract = caller_context
contract_declarer = caller_context
elif isinstance(caller_context, Function): elif isinstance(caller_context, Function):
function = caller_context function = caller_context
contract = function.contract contract = function.contract
contract_declarer = function.contract_declarer
else: else:
raise ParsingError('Incorrect caller context') raise ParsingError('Incorrect caller context')
@ -90,24 +106,35 @@ def find_variable(var_name, caller_context, referenced_declaration=None):
if var_name and var_name in func_variables_ptr: if var_name and var_name in func_variables_ptr:
return func_variables_ptr[var_name] return func_variables_ptr[var_name]
contract_variables = contract.variables_as_dict() # variable are looked from the contract declarer
contract_variables = contract_declarer.variables_as_dict()
if var_name in contract_variables: if var_name in contract_variables:
return contract_variables[var_name] return contract_variables[var_name]
# A state variable can be a pointer # A state variable can be a pointer
conc_variables_ptr = {get_pointer_name(f) : f for f in contract.variables} conc_variables_ptr = {get_pointer_name(f) : f for f in contract_declarer.variables}
if var_name and var_name in conc_variables_ptr: if var_name and var_name in conc_variables_ptr:
return conc_variables_ptr[var_name] return conc_variables_ptr[var_name]
if is_super:
functions = contract.functions_as_dict() getter_available = lambda f: f.available_functions_as_dict().items()
d = {f.canonical_name:f for f in contract.functions}
functions = {f.full_name:f for f in contract.available_elements_from_inheritances(d, getter_available).values()}
else:
functions = contract.available_functions_as_dict()
if var_name in functions: if var_name in functions:
return functions[var_name] return functions[var_name]
modifiers = contract.modifiers_as_dict() if is_super:
getter_available = lambda m: m.available_modifiers_as_dict().items()
d = {m.canonical_name: m for m in contract.modifiers}
modifiers = {m.full_name: m for m in contract.available_elements_from_inheritances(d, getter_available).values()}
else:
modifiers = contract.available_modifiers_as_dict()
if var_name in modifiers: if var_name in modifiers:
return modifiers[var_name] return modifiers[var_name]
# structures are looked on the contract declarer
structures = contract.structures_as_dict() structures = contract.structures_as_dict()
if var_name in structures: if var_name in structures:
return structures[var_name] return structures[var_name]
@ -530,6 +557,7 @@ def parse_expression(expression, caller_context):
referenced_declaration = expression['referencedDeclaration'] referenced_declaration = expression['referencedDeclaration']
else: else:
referenced_declaration = None referenced_declaration = None
var = find_variable(value, caller_context, referenced_declaration) var = find_variable(value, caller_context, referenced_declaration)
identifier = Identifier(var) identifier = Identifier(var)
@ -571,18 +599,7 @@ def parse_expression(expression, caller_context):
member_expression = parse_expression(children[0], caller_context) member_expression = parse_expression(children[0], caller_context)
if str(member_expression) == 'super': if str(member_expression) == 'super':
super_name = parse_super_name(expression, is_compact_ast) super_name = parse_super_name(expression, is_compact_ast)
if isinstance(caller_context, Contract): var = find_variable(super_name, caller_context, is_super=True)
inheritance = caller_context.inheritance
else:
assert isinstance(caller_context, Function)
inheritance = caller_context.contract.inheritance
var = None
for father in inheritance:
try:
var = find_variable(super_name, father)
break
except VariableNotFound:
continue
if var is None: if var is None:
raise VariableNotFound('Variable not found: {}'.format(super_name)) raise VariableNotFound('Variable not found: {}'.format(super_name))
return SuperIdentifier(var) return SuperIdentifier(var)

@ -59,7 +59,7 @@ def _find_from_type_name(name, contract, contracts, structures, enums):
all_enums = [item for sublist in all_enums for item in sublist] all_enums = [item for sublist in all_enums for item in sublist]
var_type = next((e for e in all_enums if e.name == enum_name), None) var_type = next((e for e in all_enums if e.name == enum_name), None)
if not var_type: if not var_type:
var_type = next((e for e in all_enums if e.contract.name+"."+e.name == enum_name), None) var_type = next((e for e in all_enums if e.canonical_name == enum_name), None)
if not var_type: if not var_type:
# any contract can refer to another contract's structure # any contract can refer to another contract's structure
name_struct = name name_struct = name
@ -70,14 +70,14 @@ def _find_from_type_name(name, contract, contracts, structures, enums):
all_structures = [item for sublist in all_structures for item in sublist] all_structures = [item for sublist in all_structures for item in sublist]
var_type = next((st for st in all_structures if st.name == name_struct), None) var_type = next((st for st in all_structures if st.name == name_struct), None)
if not var_type: if not var_type:
var_type = next((st for st in all_structures if st.contract.name+"."+st.name == name_struct), None) var_type = next((st for st in all_structures if st.canonical_name == name_struct), None)
# case where struct xxx.xx[] where not well formed in the AST # case where struct xxx.xx[] where not well formed in the AST
if not var_type: if not var_type:
depth = 0 depth = 0
while name_struct.endswith('[]'): while name_struct.endswith('[]'):
name_struct = name_struct[0:-2] name_struct = name_struct[0:-2]
depth+=1 depth+=1
var_type = next((st for st in all_structures if st.contract.name+"."+st.name == name_struct), None) var_type = next((st for st in all_structures if st.canonical_name == name_struct), None)
if var_type: if var_type:
return ArrayType(UserDefinedType(var_type), Literal(depth, 'uint256')) return ArrayType(UserDefinedType(var_type), Literal(depth, 'uint256'))

@ -19,7 +19,7 @@ def detect_c3_function_shadowing(contract):
for i in range(0, len(contract.immediate_inheritance) - 1): for i in range(0, len(contract.immediate_inheritance) - 1):
inherited_contract1 = contract.immediate_inheritance[i] inherited_contract1 = contract.immediate_inheritance[i]
for function1 in inherited_contract1.functions_and_modifiers: for function1 in inherited_contract1.functions_and_modifiers_declared:
# If this function has already be handled or is unimplemented, we skip it # If this function has already be handled or is unimplemented, we skip it
if function1.full_name in results or function1.is_constructor or not function1.is_implemented: if function1.full_name in results or function1.is_constructor or not function1.is_implemented:
continue continue
@ -61,7 +61,7 @@ def detect_direct_function_shadowing(contract):
function (could have provided it through inheritance, does not need to directly define it). function (could have provided it through inheritance, does not need to directly define it).
-overshadowed_function is the function definition which is overshadowed by the provided contract's definition. -overshadowed_function is the function definition which is overshadowed by the provided contract's definition.
""" """
functions_declared = {function.full_name: function for function in contract.functions_and_modifiers_not_inherited} functions_declared = {function.full_name: function for function in contract.functions_and_modifiers_declared}
results = {} results = {}
for base_contract in reversed(contract.immediate_inheritance): for base_contract in reversed(contract.immediate_inheritance):
for base_function in base_contract.functions_and_modifiers: for base_function in base_contract.functions_and_modifiers:
@ -109,7 +109,7 @@ def detect_function_shadowing(contracts, direct_shadowing=True, indirect_shadowi
for y in range(x + 1, len(colliding_functions)): for y in range(x + 1, len(colliding_functions)):
# The same function definition can appear more than once in the inheritance chain, # The same function definition can appear more than once in the inheritance chain,
# overshadowing items between, so it is important to remember to filter it out here. # overshadowing items between, so it is important to remember to filter it out here.
if colliding_functions[y][1].contract != colliding_functions[x][1].contract: if colliding_functions[y][1].contract_declarer != colliding_functions[x][1].contract_declarer:
results.add((contract, colliding_functions[y][0], colliding_functions[y][1], results.add((contract, colliding_functions[y][0], colliding_functions[y][1],
colliding_functions[x][0], colliding_functions[x][1])) colliding_functions[x][0], colliding_functions[x][1]))
@ -128,8 +128,7 @@ def detect_state_variable_shadowing(contracts):
""" """
results = set() results = set()
for contract in contracts: for contract in contracts:
variables_declared = {variable.name: variable for variable in contract.variables variables_declared = {variable.name: variable for variable in contract.state_variables_declared}
if variable.contract == contract}
for immediate_base_contract in contract.immediate_inheritance: for immediate_base_contract in contract.immediate_inheritance:
for variable in immediate_base_contract.variables: for variable in immediate_base_contract.variables:
if variable.name in variables_declared: if variable.name in variables_declared:

@ -129,7 +129,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
val = TupleVariable(self._node) val = TupleVariable(self._node)
else: else:
val = TemporaryVariable(self._node) val = TemporaryVariable(self._node)
internal_call = InternalCall(called, called.contract, len(args), val, expression.type_call) internal_call = InternalCall(called, len(args), val, expression.type_call)
self._result.append(internal_call) self._result.append(internal_call)
set_val(expression, val) set_val(expression, val)
else: else:

@ -1,6 +1,6 @@
INFO:CheckInitialization:Run initialization checks... (see https://github.com/crytic/slither/wiki/Upgradeability-Checks#initialization-checks) INFO:CheckInitialization:Run initialization checks... (see https://github.com/crytic/slither/wiki/Upgradeability-Checks#initialization-checks)
INFO:CheckInitialization:Contract_lack_to_call_modifier.initialize does not call initializer INFO:CheckInitialization:Contract_lack_to_call_modifier.initialize() does not call initializer
INFO:CheckInitialization:Missing call to Contract_no_bug.initialize in Contract_not_called_super_init INFO:CheckInitialization:Missing call to Contract_no_bug.initialize() in Contract_not_called_super_init
INFO:CheckInitialization:Contract_no_bug.initialize() is called multiple time in Contract_double_call INFO:CheckInitialization:Contract_no_bug.initialize() is called multiple time in Contract_double_call
INFO:CheckInitialization:Check the deployement script to ensure that these functions are called: INFO:CheckInitialization:Check the deployement script to ensure that these functions are called:
Contract_no_bug needs to be initialized by initialize() Contract_no_bug needs to be initialized by initialize()

@ -7,7 +7,7 @@
"check": "arbitrary-send", "check": "arbitrary-send",
"impact": "High", "impact": "High",
"confidence": "Medium", "confidence": "Medium",
"description": "Test.direct (tests/arbitrary_send-0.5.1.sol#11-13) sends eth to arbitrary user\n\tDangerous calls:\n\t- msg.sender.send(address(this).balance) (tests/arbitrary_send-0.5.1.sol#12)\n", "description": "Test.direct() (tests/arbitrary_send-0.5.1.sol#11-13) sends eth to arbitrary user\n\tDangerous calls:\n\t- msg.sender.send(address(this).balance) (tests/arbitrary_send-0.5.1.sol#12)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -192,7 +192,7 @@
"check": "arbitrary-send", "check": "arbitrary-send",
"impact": "High", "impact": "High",
"confidence": "Medium", "confidence": "Medium",
"description": "Test.indirect (tests/arbitrary_send-0.5.1.sol#19-21) sends eth to arbitrary user\n\tDangerous calls:\n\t- destination.send(address(this).balance) (tests/arbitrary_send-0.5.1.sol#20)\n", "description": "Test.indirect() (tests/arbitrary_send-0.5.1.sol#19-21) sends eth to arbitrary user\n\tDangerous calls:\n\t- destination.send(address(this).balance) (tests/arbitrary_send-0.5.1.sol#20)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,8 +1,8 @@
INFO:Detectors: INFO:Detectors:
Test.direct (tests/arbitrary_send-0.5.1.sol#11-13) sends eth to arbitrary user Test.direct() (tests/arbitrary_send-0.5.1.sol#11-13) sends eth to arbitrary user
Dangerous calls: Dangerous calls:
- msg.sender.send(address(this).balance) (tests/arbitrary_send-0.5.1.sol#12) - msg.sender.send(address(this).balance) (tests/arbitrary_send-0.5.1.sol#12)
Test.indirect (tests/arbitrary_send-0.5.1.sol#19-21) sends eth to arbitrary user Test.indirect() (tests/arbitrary_send-0.5.1.sol#19-21) sends eth to arbitrary user
Dangerous calls: Dangerous calls:
- destination.send(address(this).balance) (tests/arbitrary_send-0.5.1.sol#20) - destination.send(address(this).balance) (tests/arbitrary_send-0.5.1.sol#20)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#functions-that-send-ether-to-arbitrary-destinations Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#functions-that-send-ether-to-arbitrary-destinations

@ -7,7 +7,7 @@
"check": "arbitrary-send", "check": "arbitrary-send",
"impact": "High", "impact": "High",
"confidence": "Medium", "confidence": "Medium",
"description": "Test.direct (tests/arbitrary_send.sol#11-13) sends eth to arbitrary user\n\tDangerous calls:\n\t- msg.sender.send(address(this).balance) (tests/arbitrary_send.sol#12)\n", "description": "Test.direct() (tests/arbitrary_send.sol#11-13) sends eth to arbitrary user\n\tDangerous calls:\n\t- msg.sender.send(address(this).balance) (tests/arbitrary_send.sol#12)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -192,7 +192,7 @@
"check": "arbitrary-send", "check": "arbitrary-send",
"impact": "High", "impact": "High",
"confidence": "Medium", "confidence": "Medium",
"description": "Test.indirect (tests/arbitrary_send.sol#19-21) sends eth to arbitrary user\n\tDangerous calls:\n\t- destination.send(address(this).balance) (tests/arbitrary_send.sol#20)\n", "description": "Test.indirect() (tests/arbitrary_send.sol#19-21) sends eth to arbitrary user\n\tDangerous calls:\n\t- destination.send(address(this).balance) (tests/arbitrary_send.sol#20)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,8 +1,8 @@
INFO:Detectors: INFO:Detectors:
Test.direct (tests/arbitrary_send.sol#11-13) sends eth to arbitrary user Test.direct() (tests/arbitrary_send.sol#11-13) sends eth to arbitrary user
Dangerous calls: Dangerous calls:
- msg.sender.send(address(this).balance) (tests/arbitrary_send.sol#12) - msg.sender.send(address(this).balance) (tests/arbitrary_send.sol#12)
Test.indirect (tests/arbitrary_send.sol#19-21) sends eth to arbitrary user Test.indirect() (tests/arbitrary_send.sol#19-21) sends eth to arbitrary user
Dangerous calls: Dangerous calls:
- destination.send(address(this).balance) (tests/arbitrary_send.sol#20) - destination.send(address(this).balance) (tests/arbitrary_send.sol#20)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#functions-that-send-ether-to-arbitrary-destinations Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#functions-that-send-ether-to-arbitrary-destinations

@ -7,7 +7,7 @@
"check": "suicidal", "check": "suicidal",
"impact": "High", "impact": "High",
"confidence": "High", "confidence": "High",
"description": "C.i_am_a_backdoor (tests/backdoor.sol#4-6) allows anyone to destruct the contract\n", "description": "C.i_am_a_backdoor() (tests/backdoor.sol#4-6) allows anyone to destruct the contract\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,5 +1,5 @@
INFO:Detectors: INFO:Detectors:
C.i_am_a_backdoor (tests/backdoor.sol#4-6) allows anyone to destruct the contract C.i_am_a_backdoor() (tests/backdoor.sol#4-6) allows anyone to destruct the contract
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#suicidal Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#suicidal
INFO:Slither:/home/travis/build/crytic/slither/scripts/../tests/expected_json/backdoor.suicidal.json exists already, the overwrite is prevented INFO:Slither:/home/travis/build/crytic/slither/scripts/../tests/expected_json/backdoor.suicidal.json exists already, the overwrite is prevented
INFO:Slither:tests/backdoor.sol analyzed (1 contracts), 1 result(s) found INFO:Slither:tests/backdoor.sol analyzed (1 contracts), 1 result(s) found

@ -7,7 +7,7 @@
"check": "constant-function", "check": "constant-function",
"impact": "Medium", "impact": "Medium",
"confidence": "Medium", "confidence": "Medium",
"description": "Constant.test_assembly_bug (tests/constant-0.5.1.sol#15-17) is declared view but contains assembly code\n", "description": "Constant.test_assembly_bug() (tests/constant-0.5.1.sol#15-17) is declared view but contains assembly code\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,4 +1,4 @@
INFO:Detectors: INFO:Detectors:
Constant.test_assembly_bug (tests/constant-0.5.1.sol#15-17) is declared view but contains assembly code Constant.test_assembly_bug() (tests/constant-0.5.1.sol#15-17) is declared view but contains assembly code
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#constant-functions-changing-the-state Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#constant-functions-changing-the-state
INFO:Slither:tests/constant-0.5.1.sol analyzed (1 contracts), 1 result(s) found INFO:Slither:tests/constant-0.5.1.sol analyzed (1 contracts), 1 result(s) found

@ -7,7 +7,7 @@
"check": "constant-function", "check": "constant-function",
"impact": "Medium", "impact": "Medium",
"confidence": "Medium", "confidence": "Medium",
"description": "Constant.test_view_bug (tests/constant.sol#5-7) is declared view but changes state variables:\n\t- Constant.a\n", "description": "Constant.test_view_bug() (tests/constant.sol#5-7) is declared view but changes state variables:\n\t- Constant.a\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -141,7 +141,7 @@
"check": "constant-function", "check": "constant-function",
"impact": "Medium", "impact": "Medium",
"confidence": "Medium", "confidence": "Medium",
"description": "Constant.test_constant_bug (tests/constant.sol#9-11) is declared view but changes state variables:\n\t- Constant.a\n", "description": "Constant.test_constant_bug() (tests/constant.sol#9-11) is declared view but changes state variables:\n\t- Constant.a\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -275,7 +275,7 @@
"check": "constant-function", "check": "constant-function",
"impact": "Medium", "impact": "Medium",
"confidence": "Medium", "confidence": "Medium",
"description": "Constant.test_assembly_bug (tests/constant.sol#22-24) is declared view but contains assembly code\n", "description": "Constant.test_assembly_bug() (tests/constant.sol#22-24) is declared view but contains assembly code\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,8 +1,8 @@
INFO:Detectors: INFO:Detectors:
Constant.test_view_bug (tests/constant.sol#5-7) is declared view but changes state variables: Constant.test_view_bug() (tests/constant.sol#5-7) is declared view but changes state variables:
- Constant.a - Constant.a
Constant.test_constant_bug (tests/constant.sol#9-11) is declared view but changes state variables: Constant.test_constant_bug() (tests/constant.sol#9-11) is declared view but changes state variables:
- Constant.a - Constant.a
Constant.test_assembly_bug (tests/constant.sol#22-24) is declared view but contains assembly code Constant.test_assembly_bug() (tests/constant.sol#22-24) is declared view but contains assembly code
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#constant-functions-changing-the-state Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#constant-functions-changing-the-state
INFO:Slither:tests/constant.sol analyzed (1 contracts), 3 result(s) found INFO:Slither:tests/constant.sol analyzed (1 contracts), 3 result(s) found

@ -7,7 +7,7 @@
"check": "external-function", "check": "external-function",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "ContractWithFunctionNotCalled.funcNotCalled3 (tests/external_function.sol#13-15) should be declared external\n", "description": "ContractWithFunctionNotCalled.funcNotCalled3() (tests/external_function.sol#13-15) should be declared external\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -72,7 +72,7 @@
"check": "external-function", "check": "external-function",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "ContractWithFunctionNotCalled.funcNotCalled2 (tests/external_function.sol#17-19) should be declared external\n", "description": "ContractWithFunctionNotCalled.funcNotCalled2() (tests/external_function.sol#17-19) should be declared external\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -137,7 +137,7 @@
"check": "external-function", "check": "external-function",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "ContractWithFunctionNotCalled.funcNotCalled (tests/external_function.sol#21-23) should be declared external\n", "description": "ContractWithFunctionNotCalled.funcNotCalled() (tests/external_function.sol#21-23) should be declared external\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -202,7 +202,7 @@
"check": "external-function", "check": "external-function",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "ContractWithFunctionNotCalled2.funcNotCalled (tests/external_function.sol#32-39) should be declared external\n", "description": "ContractWithFunctionNotCalled2.funcNotCalled() (tests/external_function.sol#32-39) should be declared external\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,7 +1,7 @@
INFO:Detectors: INFO:Detectors:
ContractWithFunctionNotCalled.funcNotCalled3 (tests/external_function.sol#13-15) should be declared external ContractWithFunctionNotCalled.funcNotCalled3() (tests/external_function.sol#13-15) should be declared external
ContractWithFunctionNotCalled.funcNotCalled2 (tests/external_function.sol#17-19) should be declared external ContractWithFunctionNotCalled.funcNotCalled2() (tests/external_function.sol#17-19) should be declared external
ContractWithFunctionNotCalled.funcNotCalled (tests/external_function.sol#21-23) should be declared external ContractWithFunctionNotCalled.funcNotCalled() (tests/external_function.sol#21-23) should be declared external
ContractWithFunctionNotCalled2.funcNotCalled (tests/external_function.sol#32-39) should be declared external ContractWithFunctionNotCalled2.funcNotCalled() (tests/external_function.sol#32-39) should be declared external
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#public-function-that-could-be-declared-as-external Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#public-function-that-could-be-declared-as-external
INFO:Slither:tests/external_function.sol analyzed (5 contracts), 4 result(s) found INFO:Slither:tests/external_function.sol analyzed (5 contracts), 4 result(s) found

@ -7,7 +7,7 @@
"check": "incorrect-equality", "check": "incorrect-equality",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "ERC20TestBalance.bad0 (tests/incorrect_equality.sol#21-23) uses a dangerous strict equality:\n\t- require(bool)(erc.balanceOf(address(this)) == 10)\n", "description": "ERC20TestBalance.bad0(ERC20Function) (tests/incorrect_equality.sol#21-23) uses a dangerous strict equality:\n\t- require(bool)(erc.balanceOf(address(this)) == 10)\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",
@ -148,7 +148,7 @@
"check": "incorrect-equality", "check": "incorrect-equality",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "ERC20TestBalance.bad1 (tests/incorrect_equality.sol#25-27) uses a dangerous strict equality:\n\t- require(bool)(erc.balanceOf(msg.sender) == 10)\n", "description": "ERC20TestBalance.bad1(ERC20Variable) (tests/incorrect_equality.sol#25-27) uses a dangerous strict equality:\n\t- require(bool)(erc.balanceOf(msg.sender) == 10)\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",
@ -289,7 +289,7 @@
"check": "incorrect-equality", "check": "incorrect-equality",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "TestContractBalance.bad0 (tests/incorrect_equality.sol#32-35) uses a dangerous strict equality:\n\t- require(bool)(address(address(this)).balance == 10000000000000000000)\n", "description": "TestContractBalance.bad0() (tests/incorrect_equality.sol#32-35) uses a dangerous strict equality:\n\t- require(bool)(address(address(this)).balance == 10000000000000000000)\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",
@ -530,7 +530,7 @@
"check": "incorrect-equality", "check": "incorrect-equality",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "TestContractBalance.bad1 (tests/incorrect_equality.sol#37-40) uses a dangerous strict equality:\n\t- require(bool)(10000000000000000000 == address(address(this)).balance)\n", "description": "TestContractBalance.bad1() (tests/incorrect_equality.sol#37-40) uses a dangerous strict equality:\n\t- require(bool)(10000000000000000000 == address(address(this)).balance)\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",
@ -771,7 +771,7 @@
"check": "incorrect-equality", "check": "incorrect-equality",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "TestContractBalance.bad2 (tests/incorrect_equality.sol#42-45) uses a dangerous strict equality:\n\t- require(bool)(address(this).balance == 10000000000000000000)\n", "description": "TestContractBalance.bad2() (tests/incorrect_equality.sol#42-45) uses a dangerous strict equality:\n\t- require(bool)(address(this).balance == 10000000000000000000)\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",
@ -1012,7 +1012,7 @@
"check": "incorrect-equality", "check": "incorrect-equality",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "TestContractBalance.bad3 (tests/incorrect_equality.sol#47-50) uses a dangerous strict equality:\n\t- require(bool)(10000000000000000000 == address(this).balance)\n", "description": "TestContractBalance.bad3() (tests/incorrect_equality.sol#47-50) uses a dangerous strict equality:\n\t- require(bool)(10000000000000000000 == address(this).balance)\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",
@ -1253,7 +1253,7 @@
"check": "incorrect-equality", "check": "incorrect-equality",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "TestContractBalance.bad4 (tests/incorrect_equality.sol#52-57) uses a dangerous strict equality:\n\t- balance == 10000000000000000000\n", "description": "TestContractBalance.bad4() (tests/incorrect_equality.sol#52-57) uses a dangerous strict equality:\n\t- balance == 10000000000000000000\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",
@ -1500,7 +1500,7 @@
"check": "incorrect-equality", "check": "incorrect-equality",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "TestContractBalance.bad5 (tests/incorrect_equality.sol#59-64) uses a dangerous strict equality:\n\t- 10000000000000000000 == balance\n", "description": "TestContractBalance.bad5() (tests/incorrect_equality.sol#59-64) uses a dangerous strict equality:\n\t- 10000000000000000000 == balance\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",
@ -1747,7 +1747,7 @@
"check": "incorrect-equality", "check": "incorrect-equality",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "TestContractBalance.bad6 (tests/incorrect_equality.sol#66-71) uses a dangerous strict equality:\n\t- balance == 10000000000000000000\n", "description": "TestContractBalance.bad6() (tests/incorrect_equality.sol#66-71) uses a dangerous strict equality:\n\t- balance == 10000000000000000000\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",
@ -1994,7 +1994,7 @@
"check": "incorrect-equality", "check": "incorrect-equality",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "TestSolidityKeyword.bad0 (tests/incorrect_equality.sol#123-125) uses a dangerous strict equality:\n\t- require(bool)(now == 0)\n", "description": "TestSolidityKeyword.bad0() (tests/incorrect_equality.sol#123-125) uses a dangerous strict equality:\n\t- require(bool)(now == 0)\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",
@ -2171,7 +2171,7 @@
"check": "incorrect-equality", "check": "incorrect-equality",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "TestSolidityKeyword.bad1 (tests/incorrect_equality.sol#127-129) uses a dangerous strict equality:\n\t- require(bool)(block.number == 0)\n", "description": "TestSolidityKeyword.bad1() (tests/incorrect_equality.sol#127-129) uses a dangerous strict equality:\n\t- require(bool)(block.number == 0)\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",
@ -2348,7 +2348,7 @@
"check": "incorrect-equality", "check": "incorrect-equality",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "TestSolidityKeyword.bad2 (tests/incorrect_equality.sol#131-133) uses a dangerous strict equality:\n\t- require(bool)(block.number == 0)\n", "description": "TestSolidityKeyword.bad2() (tests/incorrect_equality.sol#131-133) uses a dangerous strict equality:\n\t- require(bool)(block.number == 0)\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",

@ -1,27 +1,27 @@
INFO:Detectors: INFO:Detectors:
ERC20TestBalance.bad0 (tests/incorrect_equality.sol#21-23) uses a dangerous strict equality: ERC20TestBalance.bad0(ERC20Function) (tests/incorrect_equality.sol#21-23) uses a dangerous strict equality:
- require(bool)(erc.balanceOf(address(this)) == 10) - require(bool)(erc.balanceOf(address(this)) == 10)
ERC20TestBalance.bad1 (tests/incorrect_equality.sol#25-27) uses a dangerous strict equality: ERC20TestBalance.bad1(ERC20Variable) (tests/incorrect_equality.sol#25-27) uses a dangerous strict equality:
- require(bool)(erc.balanceOf(msg.sender) == 10) - require(bool)(erc.balanceOf(msg.sender) == 10)
TestContractBalance.bad0 (tests/incorrect_equality.sol#32-35) uses a dangerous strict equality: TestContractBalance.bad0() (tests/incorrect_equality.sol#32-35) uses a dangerous strict equality:
- require(bool)(address(address(this)).balance == 10000000000000000000) - require(bool)(address(address(this)).balance == 10000000000000000000)
TestContractBalance.bad1 (tests/incorrect_equality.sol#37-40) uses a dangerous strict equality: TestContractBalance.bad1() (tests/incorrect_equality.sol#37-40) uses a dangerous strict equality:
- require(bool)(10000000000000000000 == address(address(this)).balance) - require(bool)(10000000000000000000 == address(address(this)).balance)
TestContractBalance.bad2 (tests/incorrect_equality.sol#42-45) uses a dangerous strict equality: TestContractBalance.bad2() (tests/incorrect_equality.sol#42-45) uses a dangerous strict equality:
- require(bool)(address(this).balance == 10000000000000000000) - require(bool)(address(this).balance == 10000000000000000000)
TestContractBalance.bad3 (tests/incorrect_equality.sol#47-50) uses a dangerous strict equality: TestContractBalance.bad3() (tests/incorrect_equality.sol#47-50) uses a dangerous strict equality:
- require(bool)(10000000000000000000 == address(this).balance) - require(bool)(10000000000000000000 == address(this).balance)
TestContractBalance.bad4 (tests/incorrect_equality.sol#52-57) uses a dangerous strict equality: TestContractBalance.bad4() (tests/incorrect_equality.sol#52-57) uses a dangerous strict equality:
- balance == 10000000000000000000 - balance == 10000000000000000000
TestContractBalance.bad5 (tests/incorrect_equality.sol#59-64) uses a dangerous strict equality: TestContractBalance.bad5() (tests/incorrect_equality.sol#59-64) uses a dangerous strict equality:
- 10000000000000000000 == balance - 10000000000000000000 == balance
TestContractBalance.bad6 (tests/incorrect_equality.sol#66-71) uses a dangerous strict equality: TestContractBalance.bad6() (tests/incorrect_equality.sol#66-71) uses a dangerous strict equality:
- balance == 10000000000000000000 - balance == 10000000000000000000
TestSolidityKeyword.bad0 (tests/incorrect_equality.sol#123-125) uses a dangerous strict equality: TestSolidityKeyword.bad0() (tests/incorrect_equality.sol#123-125) uses a dangerous strict equality:
- require(bool)(now == 0) - require(bool)(now == 0)
TestSolidityKeyword.bad1 (tests/incorrect_equality.sol#127-129) uses a dangerous strict equality: TestSolidityKeyword.bad1() (tests/incorrect_equality.sol#127-129) uses a dangerous strict equality:
- require(bool)(block.number == 0) - require(bool)(block.number == 0)
TestSolidityKeyword.bad2 (tests/incorrect_equality.sol#131-133) uses a dangerous strict equality: TestSolidityKeyword.bad2() (tests/incorrect_equality.sol#131-133) uses a dangerous strict equality:
- require(bool)(block.number == 0) - require(bool)(block.number == 0)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#dangerous-strict-equalities Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#dangerous-strict-equalities
INFO:Slither:tests/incorrect_equality.sol analyzed (5 contracts), 12 result(s) found INFO:Slither:tests/incorrect_equality.sol analyzed (5 contracts), 12 result(s) found

@ -7,7 +7,7 @@
"check": "erc20-interface", "check": "erc20-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: transfer (tests/incorrect_erc20_interface.sol#4)\n", "description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: transfer(address,uint256) (tests/incorrect_erc20_interface.sol#4)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -59,7 +59,7 @@
"check": "erc20-interface", "check": "erc20-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: approve (tests/incorrect_erc20_interface.sol#5)\n", "description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: approve(address,uint256) (tests/incorrect_erc20_interface.sol#5)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -111,7 +111,7 @@
"check": "erc20-interface", "check": "erc20-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: transferFrom (tests/incorrect_erc20_interface.sol#6)\n", "description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: transferFrom(address,address,uint256) (tests/incorrect_erc20_interface.sol#6)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -163,7 +163,7 @@
"check": "erc20-interface", "check": "erc20-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: totalSupply (tests/incorrect_erc20_interface.sol#7)\n", "description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: totalSupply() (tests/incorrect_erc20_interface.sol#7)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -215,7 +215,7 @@
"check": "erc20-interface", "check": "erc20-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: balanceOf (tests/incorrect_erc20_interface.sol#8)\n", "description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: balanceOf(address) (tests/incorrect_erc20_interface.sol#8)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -267,7 +267,7 @@
"check": "erc20-interface", "check": "erc20-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: allowance (tests/incorrect_erc20_interface.sol#9)\n", "description": "Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: allowance(address,address) (tests/incorrect_erc20_interface.sol#9)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,9 +1,9 @@
INFO:Detectors: INFO:Detectors:
Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: transfer (tests/incorrect_erc20_interface.sol#4) Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: transfer(address,uint256) (tests/incorrect_erc20_interface.sol#4)
Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: approve (tests/incorrect_erc20_interface.sol#5) Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: approve(address,uint256) (tests/incorrect_erc20_interface.sol#5)
Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: transferFrom (tests/incorrect_erc20_interface.sol#6) Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: transferFrom(address,address,uint256) (tests/incorrect_erc20_interface.sol#6)
Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: totalSupply (tests/incorrect_erc20_interface.sol#7) Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: totalSupply() (tests/incorrect_erc20_interface.sol#7)
Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: balanceOf (tests/incorrect_erc20_interface.sol#8) Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: balanceOf(address) (tests/incorrect_erc20_interface.sol#8)
Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: allowance (tests/incorrect_erc20_interface.sol#9) Token (tests/incorrect_erc20_interface.sol#3-10) has incorrect ERC20 function interface: allowance(address,address) (tests/incorrect_erc20_interface.sol#9)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface
INFO:Slither:tests/incorrect_erc20_interface.sol analyzed (1 contracts), 6 result(s) found INFO:Slither:tests/incorrect_erc20_interface.sol analyzed (1 contracts), 6 result(s) found

@ -7,7 +7,7 @@
"check": "erc721-interface", "check": "erc721-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: supportsInterface (tests/incorrect_erc721_interface.sol#4)\n", "description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: supportsInterface(bytes4) (tests/incorrect_erc721_interface.sol#4)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -54,7 +54,7 @@
"check": "erc721-interface", "check": "erc721-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: balanceOf (tests/incorrect_erc721_interface.sol#7)\n", "description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: balanceOf(address) (tests/incorrect_erc721_interface.sol#7)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -109,7 +109,7 @@
"check": "erc721-interface", "check": "erc721-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: ownerOf (tests/incorrect_erc721_interface.sol#8)\n", "description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: ownerOf(uint256) (tests/incorrect_erc721_interface.sol#8)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -164,7 +164,7 @@
"check": "erc721-interface", "check": "erc721-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: safeTransferFrom (tests/incorrect_erc721_interface.sol#9)\n", "description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: safeTransferFrom(address,address,uint256,bytes) (tests/incorrect_erc721_interface.sol#9)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -219,7 +219,7 @@
"check": "erc721-interface", "check": "erc721-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: safeTransferFrom (tests/incorrect_erc721_interface.sol#10)\n", "description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: safeTransferFrom(address,address,uint256) (tests/incorrect_erc721_interface.sol#10)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -274,7 +274,7 @@
"check": "erc721-interface", "check": "erc721-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: transferFrom (tests/incorrect_erc721_interface.sol#11)\n", "description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: transferFrom(address,address,uint256) (tests/incorrect_erc721_interface.sol#11)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -329,7 +329,7 @@
"check": "erc721-interface", "check": "erc721-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: approve (tests/incorrect_erc721_interface.sol#12)\n", "description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: approve(address,uint256) (tests/incorrect_erc721_interface.sol#12)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -384,7 +384,7 @@
"check": "erc721-interface", "check": "erc721-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: setApprovalForAll (tests/incorrect_erc721_interface.sol#13)\n", "description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: setApprovalForAll(address,bool) (tests/incorrect_erc721_interface.sol#13)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -439,7 +439,7 @@
"check": "erc721-interface", "check": "erc721-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: getApproved (tests/incorrect_erc721_interface.sol#14)\n", "description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: getApproved(uint256) (tests/incorrect_erc721_interface.sol#14)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -494,7 +494,7 @@
"check": "erc721-interface", "check": "erc721-interface",
"impact": "Medium", "impact": "Medium",
"confidence": "High", "confidence": "High",
"description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: isApprovedForAll (tests/incorrect_erc721_interface.sol#15)\n", "description": "Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: isApprovedForAll(address,address) (tests/incorrect_erc721_interface.sol#15)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,13 +1,13 @@
INFO:Detectors: INFO:Detectors:
Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: supportsInterface (tests/incorrect_erc721_interface.sol#4) Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: supportsInterface(bytes4) (tests/incorrect_erc721_interface.sol#4)
Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: balanceOf (tests/incorrect_erc721_interface.sol#7) Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: balanceOf(address) (tests/incorrect_erc721_interface.sol#7)
Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: ownerOf (tests/incorrect_erc721_interface.sol#8) Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: ownerOf(uint256) (tests/incorrect_erc721_interface.sol#8)
Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: safeTransferFrom (tests/incorrect_erc721_interface.sol#9) Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: safeTransferFrom(address,address,uint256,bytes) (tests/incorrect_erc721_interface.sol#9)
Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: safeTransferFrom (tests/incorrect_erc721_interface.sol#10) Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: safeTransferFrom(address,address,uint256) (tests/incorrect_erc721_interface.sol#10)
Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: transferFrom (tests/incorrect_erc721_interface.sol#11) Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: transferFrom(address,address,uint256) (tests/incorrect_erc721_interface.sol#11)
Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: approve (tests/incorrect_erc721_interface.sol#12) Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: approve(address,uint256) (tests/incorrect_erc721_interface.sol#12)
Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: setApprovalForAll (tests/incorrect_erc721_interface.sol#13) Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: setApprovalForAll(address,bool) (tests/incorrect_erc721_interface.sol#13)
Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: getApproved (tests/incorrect_erc721_interface.sol#14) Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: getApproved(uint256) (tests/incorrect_erc721_interface.sol#14)
Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: isApprovedForAll (tests/incorrect_erc721_interface.sol#15) Token (tests/incorrect_erc721_interface.sol#6-16) has incorrect ERC721 function interface: isApprovedForAll(address,address) (tests/incorrect_erc721_interface.sol#15)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc721-interface Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc721-interface
INFO:Slither:tests/incorrect_erc721_interface.sol analyzed (2 contracts), 10 result(s) found INFO:Slither:tests/incorrect_erc721_interface.sol analyzed (2 contracts), 10 result(s) found

@ -7,7 +7,7 @@
"check": "assembly", "check": "assembly",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "GetCode.at uses assembly (tests/inline_assembly_contract-0.5.1.sol#6-20)\n\t- tests/inline_assembly_contract-0.5.1.sol#7-20\n", "description": "GetCode.at(address) uses assembly (tests/inline_assembly_contract-0.5.1.sol#6-20)\n\t- tests/inline_assembly_contract-0.5.1.sol#7-20\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,5 +1,5 @@
INFO:Detectors: INFO:Detectors:
GetCode.at uses assembly (tests/inline_assembly_contract-0.5.1.sol#6-20) GetCode.at(address) uses assembly (tests/inline_assembly_contract-0.5.1.sol#6-20)
- tests/inline_assembly_contract-0.5.1.sol#7-20 - tests/inline_assembly_contract-0.5.1.sol#7-20
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#assembly-usage Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#assembly-usage
INFO:Slither:tests/inline_assembly_contract-0.5.1.sol analyzed (1 contracts), 1 result(s) found INFO:Slither:tests/inline_assembly_contract-0.5.1.sol analyzed (1 contracts), 1 result(s) found

@ -7,7 +7,7 @@
"check": "assembly", "check": "assembly",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "GetCode.at uses assembly (tests/inline_assembly_contract.sol#6-20)\n\t- tests/inline_assembly_contract.sol#7-20\n", "description": "GetCode.at(address) uses assembly (tests/inline_assembly_contract.sol#6-20)\n\t- tests/inline_assembly_contract.sol#7-20\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,5 +1,5 @@
INFO:Detectors: INFO:Detectors:
GetCode.at uses assembly (tests/inline_assembly_contract.sol#6-20) GetCode.at(address) uses assembly (tests/inline_assembly_contract.sol#6-20)
- tests/inline_assembly_contract.sol#7-20 - tests/inline_assembly_contract.sol#7-20
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#assembly-usage Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#assembly-usage
INFO:Slither:tests/inline_assembly_contract.sol analyzed (1 contracts), 1 result(s) found INFO:Slither:tests/inline_assembly_contract.sol analyzed (1 contracts), 1 result(s) found

@ -7,7 +7,7 @@
"check": "assembly", "check": "assembly",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "VectorSum.sumAsm uses assembly (tests/inline_assembly_library-0.5.1.sol#16-22)\n\t- tests/inline_assembly_library-0.5.1.sol#18-21\n", "description": "VectorSum.sumAsm(uint256[]) uses assembly (tests/inline_assembly_library-0.5.1.sol#16-22)\n\t- tests/inline_assembly_library-0.5.1.sol#18-21\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -209,7 +209,7 @@
"check": "assembly", "check": "assembly",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "VectorSum.sumPureAsm uses assembly (tests/inline_assembly_library-0.5.1.sol#25-47)\n\t- tests/inline_assembly_library-0.5.1.sol#26-47\n", "description": "VectorSum.sumPureAsm(uint256[]) uses assembly (tests/inline_assembly_library-0.5.1.sol#25-47)\n\t- tests/inline_assembly_library-0.5.1.sol#26-47\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,7 +1,7 @@
INFO:Detectors: INFO:Detectors:
VectorSum.sumAsm uses assembly (tests/inline_assembly_library-0.5.1.sol#16-22) VectorSum.sumAsm(uint256[]) uses assembly (tests/inline_assembly_library-0.5.1.sol#16-22)
- tests/inline_assembly_library-0.5.1.sol#18-21 - tests/inline_assembly_library-0.5.1.sol#18-21
VectorSum.sumPureAsm uses assembly (tests/inline_assembly_library-0.5.1.sol#25-47) VectorSum.sumPureAsm(uint256[]) uses assembly (tests/inline_assembly_library-0.5.1.sol#25-47)
- tests/inline_assembly_library-0.5.1.sol#26-47 - tests/inline_assembly_library-0.5.1.sol#26-47
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#assembly-usage Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#assembly-usage
INFO:Slither:tests/inline_assembly_library-0.5.1.sol analyzed (1 contracts), 2 result(s) found INFO:Slither:tests/inline_assembly_library-0.5.1.sol analyzed (1 contracts), 2 result(s) found

@ -7,7 +7,7 @@
"check": "assembly", "check": "assembly",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "VectorSum.sumAsm uses assembly (tests/inline_assembly_library.sol#16-22)\n\t- tests/inline_assembly_library.sol#18-21\n", "description": "VectorSum.sumAsm(uint256[]) uses assembly (tests/inline_assembly_library.sol#16-22)\n\t- tests/inline_assembly_library.sol#18-21\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -209,7 +209,7 @@
"check": "assembly", "check": "assembly",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "VectorSum.sumPureAsm uses assembly (tests/inline_assembly_library.sol#25-47)\n\t- tests/inline_assembly_library.sol#26-47\n", "description": "VectorSum.sumPureAsm(uint256[]) uses assembly (tests/inline_assembly_library.sol#25-47)\n\t- tests/inline_assembly_library.sol#26-47\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,7 +1,7 @@
INFO:Detectors: INFO:Detectors:
VectorSum.sumAsm uses assembly (tests/inline_assembly_library.sol#16-22) VectorSum.sumAsm(uint256[]) uses assembly (tests/inline_assembly_library.sol#16-22)
- tests/inline_assembly_library.sol#18-21 - tests/inline_assembly_library.sol#18-21
VectorSum.sumPureAsm uses assembly (tests/inline_assembly_library.sol#25-47) VectorSum.sumPureAsm(uint256[]) uses assembly (tests/inline_assembly_library.sol#25-47)
- tests/inline_assembly_library.sol#26-47 - tests/inline_assembly_library.sol#26-47
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#assembly-usage Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#assembly-usage
INFO:Slither:tests/inline_assembly_library.sol analyzed (1 contracts), 2 result(s) found INFO:Slither:tests/inline_assembly_library.sol analyzed (1 contracts), 2 result(s) found

@ -7,7 +7,7 @@
"check": "low-level-calls", "check": "low-level-calls",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "Low level call in Sender.send (tests/low_level_calls.sol#5-7):\n\t-_receiver.call.value(msg.value).gas(7777)() tests/low_level_calls.sol#6\n", "description": "Low level call in Sender.send(address) (tests/low_level_calls.sol#5-7):\n\t-_receiver.call.value(msg.value).gas(7777)() tests/low_level_calls.sol#6\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,5 +1,5 @@
INFO:Detectors: INFO:Detectors:
Low level call in Sender.send (tests/low_level_calls.sol#5-7): Low level call in Sender.send(address) (tests/low_level_calls.sol#5-7):
-_receiver.call.value(msg.value).gas(7777)() tests/low_level_calls.sol#6 -_receiver.call.value(msg.value).gas(7777)() tests/low_level_calls.sol#6
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#low-level-calls Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#low-level-calls
INFO:Slither:tests/low_level_calls.sol analyzed (2 contracts), 1 result(s) found INFO:Slither:tests/low_level_calls.sol analyzed (2 contracts), 1 result(s) found

@ -7,7 +7,7 @@
"check": "calls-loop", "check": "calls-loop",
"impact": "Low", "impact": "Low",
"confidence": "Medium", "confidence": "Medium",
"description": "CallInLoop.bad has external calls inside a loop: \"destinations[i].transfer(i)\" (tests/multiple_calls_in_loop.sol#11)\n", "description": "CallInLoop.bad() has external calls inside a loop: \"destinations[i].transfer(i)\" (tests/multiple_calls_in_loop.sol#11)\n",
"elements": [ "elements": [
{ {
"type": "node", "type": "node",

@ -1,4 +1,4 @@
INFO:Detectors: INFO:Detectors:
CallInLoop.bad has external calls inside a loop: "destinations[i].transfer(i)" (tests/multiple_calls_in_loop.sol#11) CallInLoop.bad() has external calls inside a loop: "destinations[i].transfer(i)" (tests/multiple_calls_in_loop.sol#11)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation/_edit#calls-inside-a-loop Reference: https://github.com/crytic/slither/wiki/Detector-Documentation/_edit#calls-inside-a-loop
INFO:Slither:tests/multiple_calls_in_loop.sol analyzed (1 contracts), 1 result(s) found INFO:Slither:tests/multiple_calls_in_loop.sol analyzed (1 contracts), 1 result(s) found

@ -176,7 +176,7 @@
"check": "naming-convention", "check": "naming-convention",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "Event 'naming.event_' (tests/naming_convention.sol#23) is not in CapWords\n", "description": "Event 'namingevent_(uint256)' (tests/naming_convention.sol#23) is not in CapWords\n",
"elements": [ "elements": [
{ {
"type": "event", "type": "event",
@ -270,7 +270,7 @@
"check": "naming-convention", "check": "naming-convention",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "Function 'naming.GetOne' (tests/naming_convention.sol#30-33) is not in mixedCase\n", "description": "Function 'naming.GetOne()' (tests/naming_convention.sol#30-33) is not in mixedCase\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -367,7 +367,7 @@
"check": "naming-convention", "check": "naming-convention",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "Parameter 'Number2' of naming.setInt (tests/naming_convention.sol#35) is not in mixedCase\n", "description": "Parameter 'Number2' of Number2 (tests/naming_convention.sol#35) is not in mixedCase\n",
"elements": [ "elements": [
{ {
"type": "variable", "type": "variable",
@ -762,7 +762,7 @@
"check": "naming-convention", "check": "naming-convention",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "Modifier 'naming.CantDo' (tests/naming_convention.sol#41-43) is not in mixedCase\n", "description": "Modifier 'naming.CantDo()' (tests/naming_convention.sol#41-43) is not in mixedCase\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -858,7 +858,7 @@
"check": "naming-convention", "check": "naming-convention",
"impact": "Informational", "impact": "Informational",
"confidence": "High", "confidence": "High",
"description": "Parameter '_used' of T.test (tests/naming_convention.sol#59) is not in mixedCase\n", "description": "Parameter '_used' of _used (tests/naming_convention.sol#59) is not in mixedCase\n",
"elements": [ "elements": [
{ {
"type": "variable", "type": "variable",

@ -1,14 +1,14 @@
INFO:Detectors: INFO:Detectors:
Contract 'naming' (tests/naming_convention.sol#3-48) is not in CapWords Contract 'naming' (tests/naming_convention.sol#3-48) is not in CapWords
Struct 'naming.test' (tests/naming_convention.sol#14-16) is not in CapWords Struct 'naming.test' (tests/naming_convention.sol#14-16) is not in CapWords
Event 'naming.event_' (tests/naming_convention.sol#23) is not in CapWords Event 'namingevent_(uint256)' (tests/naming_convention.sol#23) is not in CapWords
Function 'naming.GetOne' (tests/naming_convention.sol#30-33) is not in mixedCase Function 'naming.GetOne()' (tests/naming_convention.sol#30-33) is not in mixedCase
Parameter 'Number2' of naming.setInt (tests/naming_convention.sol#35) is not in mixedCase Parameter 'Number2' of Number2 (tests/naming_convention.sol#35) is not in mixedCase
Constant 'naming.MY_other_CONSTANT' (tests/naming_convention.sol#9) is not in UPPER_CASE_WITH_UNDERSCORES Constant 'naming.MY_other_CONSTANT' (tests/naming_convention.sol#9) is not in UPPER_CASE_WITH_UNDERSCORES
Variable 'naming.Var_One' (tests/naming_convention.sol#11) is not in mixedCase Variable 'naming.Var_One' (tests/naming_convention.sol#11) is not in mixedCase
Enum 'naming.numbers' (tests/naming_convention.sol#6) is not in CapWords Enum 'naming.numbers' (tests/naming_convention.sol#6) is not in CapWords
Modifier 'naming.CantDo' (tests/naming_convention.sol#41-43) is not in mixedCase Modifier 'naming.CantDo()' (tests/naming_convention.sol#41-43) is not in mixedCase
Parameter '_used' of T.test (tests/naming_convention.sol#59) is not in mixedCase Parameter '_used' of _used (tests/naming_convention.sol#59) is not in mixedCase
Variable 'T._myPublicVar' (tests/naming_convention.sol#56) is not in mixedCase Variable 'T._myPublicVar' (tests/naming_convention.sol#56) is not in mixedCase
Variable 'T.l' (tests/naming_convention.sol#67) used l, O, I, which should not be used Variable 'T.l' (tests/naming_convention.sol#67) used l, O, I, which should not be used
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#conformance-to-solidity-naming-conventions Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#conformance-to-solidity-naming-conventions

@ -1,5 +1,5 @@
INFO:Detectors: INFO:Detectors:
Pragma version "0.4.21" allows old versions (None) Pragma version "0.4.21" allows old versions (None)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-version-of-solidity Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-versions-of-solidity
INFO:Slither:/home/travis/build/crytic/slither/scripts/../tests/expected_json/old_solc.sol.json.solc-version.json exists already, the overwrite is prevented INFO:Slither:/home/travis/build/crytic/slither/scripts/../tests/expected_json/old_solc.sol.json.solc-version.json exists already, the overwrite is prevented
INFO:Slither:tests/old_solc.sol.json analyzed (1 contracts), 1 result(s) found INFO:Slither:tests/old_solc.sol.json analyzed (1 contracts), 1 result(s) found

@ -7,7 +7,7 @@
"check": "reentrancy-eth", "check": "reentrancy-eth",
"impact": "High", "impact": "High",
"confidence": "Medium", "confidence": "Medium",
"description": "Reentrancy in Reentrancy.withdrawBalance (tests/reentrancy-0.5.1.sol#14-22):\n\tExternal calls:\n\t- (ret,mem) = msg.sender.call.value(userBalance[msg.sender])() (tests/reentrancy-0.5.1.sol#17)\n\tState variables written after the call(s):\n\t- userBalance (tests/reentrancy-0.5.1.sol#21)\n", "description": "Reentrancy in Reentrancy.withdrawBalance() (tests/reentrancy-0.5.1.sol#14-22):\n\tExternal calls:\n\t- (ret,mem) = msg.sender.call.value(userBalance[msg.sender])() (tests/reentrancy-0.5.1.sol#17)\n\tState variables written after the call(s):\n\t- userBalance (tests/reentrancy-0.5.1.sol#21)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",
@ -348,7 +348,7 @@
"check": "reentrancy-eth", "check": "reentrancy-eth",
"impact": "High", "impact": "High",
"confidence": "Medium", "confidence": "Medium",
"description": "Reentrancy in Reentrancy.withdrawBalance_fixed_3 (tests/reentrancy-0.5.1.sol#44-53):\n\tExternal calls:\n\t- (ret,mem) = msg.sender.call.value(amount)() (tests/reentrancy-0.5.1.sol#49)\n\tState variables written after the call(s):\n\t- userBalance (tests/reentrancy-0.5.1.sol#51)\n", "description": "Reentrancy in Reentrancy.withdrawBalance_fixed_3() (tests/reentrancy-0.5.1.sol#44-53):\n\tExternal calls:\n\t- (ret,mem) = msg.sender.call.value(amount)() (tests/reentrancy-0.5.1.sol#49)\n\tState variables written after the call(s):\n\t- userBalance (tests/reentrancy-0.5.1.sol#51)\n",
"elements": [ "elements": [
{ {
"type": "function", "type": "function",

@ -1,10 +1,10 @@
INFO:Detectors: INFO:Detectors:
Reentrancy in Reentrancy.withdrawBalance (tests/reentrancy-0.5.1.sol#14-22): Reentrancy in Reentrancy.withdrawBalance() (tests/reentrancy-0.5.1.sol#14-22):
External calls: External calls:
- (ret,mem) = msg.sender.call.value(userBalance[msg.sender])() (tests/reentrancy-0.5.1.sol#17) - (ret,mem) = msg.sender.call.value(userBalance[msg.sender])() (tests/reentrancy-0.5.1.sol#17)
State variables written after the call(s): State variables written after the call(s):
- userBalance (tests/reentrancy-0.5.1.sol#21) - userBalance (tests/reentrancy-0.5.1.sol#21)
Reentrancy in Reentrancy.withdrawBalance_fixed_3 (tests/reentrancy-0.5.1.sol#44-53): Reentrancy in Reentrancy.withdrawBalance_fixed_3() (tests/reentrancy-0.5.1.sol#44-53):
External calls: External calls:
- (ret,mem) = msg.sender.call.value(amount)() (tests/reentrancy-0.5.1.sol#49) - (ret,mem) = msg.sender.call.value(amount)() (tests/reentrancy-0.5.1.sol#49)
State variables written after the call(s): State variables written after the call(s):

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save