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. 6
      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. 12
      slither/detectors/shadowing/abstract.py
  38. 32
      slither/detectors/shadowing/builtin_symbols.py
  39. 18
      slither/detectors/shadowing/local.py
  40. 14
      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. 6
      slither/detectors/statements/incorrect_strict_equality.py
  46. 8
      slither/detectors/statements/tx_origin.py
  47. 6
      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. 8
      slither/detectors/variables/unused_state_variables.py
  52. 18
      slither/printers/inheritance/inheritance_graph.py
  53. 2
      slither/printers/summary/data_depenency.py
  54. 40
      slither/printers/summary/slithir.py
  55. 36
      slither/printers/summary/slithir_ssa.py
  56. 51
      slither/slithir/convert.py
  57. 22
      slither/slithir/operations/internal_call.py
  58. 2
      slither/slithir/utils/ssa.py
  59. 97
      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_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('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 [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]
@ -86,7 +86,7 @@ def __find_target_paths(target_function, current_path=[]):
# Look through all functions
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 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(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("\n")
# 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(f"The following paths reach the specified targets:")

@ -15,7 +15,7 @@ for contract in slither.contracts:
for function in contract.functions:
# Dont explore inherited functions
if function.contract == contract:
if function.contract_declarer == contract:
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/erc20_indexed.sol "erc20-indexed"
#generate_expected_json tests/incorrect_erc20_interface.sol "erc20-interface"
#generate_expected_json tests/incorrect_erc721_interface.sol "erc721-interface"
#generate_expected_json tests/uninitialized.sol "uninitialized-state"
#generate_expected_json tests/backdoor.sol "backdoor"
#generate_expected_json tests/backdoor.sol "suicidal"
#generate_expected_json tests/pragma.0.4.24.sol "pragma"
#generate_expected_json tests/old_solc.sol.json "solc-version"
#generate_expected_json tests/reentrancy.sol "reentrancy-eth"
#generate_expected_json tests/uninitialized_storage_pointer.sol "uninitialized-storage"
#generate_expected_json tests/tx_origin.sol "tx-origin"
#generate_expected_json tests/unused_state.sol "unused-state"
#generate_expected_json tests/locked_ether.sol "locked-ether"
#generate_expected_json tests/arbitrary_send.sol "arbitrary-send"
#generate_expected_json tests/inline_assembly_contract.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/const_state_variables.sol "constable-states"
#generate_expected_json tests/external_function.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/uninitialized_local_variable.sol "uninitialized-local"
#generate_expected_json tests/controlled_delegatecall.sol "controlled-delegatecall"
#generate_expected_json tests/constant.sol "constant-function"
#generate_expected_json tests/unused_return.sol "unused-return"
#generate_expected_json tests/shadowing_state_variable.sol "shadowing-state"
#generate_expected_json tests/shadowing_abstract.sol "shadowing-abstract"
#generate_expected_json tests/timestamp.sol "timestamp"
#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_local_variable.sol "shadowing-local"
#generate_expected_json tests/solc_version_incorrect.sol "solc-version"
#generate_expected_json tests/right_to_left_override.sol "rtlo"
#generate_expected_json tests/unchecked_lowlevel.sol "unchecked-lowlevel"
generate_expected_json tests/deprecated_calls.sol "deprecated-standards"
generate_expected_json tests/erc20_indexed.sol "erc20-indexed"
generate_expected_json tests/incorrect_erc20_interface.sol "erc20-interface"
generate_expected_json tests/incorrect_erc721_interface.sol "erc721-interface"
generate_expected_json tests/uninitialized.sol "uninitialized-state"
generate_expected_json tests/backdoor.sol "backdoor"
generate_expected_json tests/backdoor.sol "suicidal"
generate_expected_json tests/pragma.0.4.24.sol "pragma"
generate_expected_json tests/old_solc.sol.json "solc-version"
generate_expected_json tests/reentrancy.sol "reentrancy-eth"
generate_expected_json tests/uninitialized_storage_pointer.sol "uninitialized-storage"
generate_expected_json tests/tx_origin.sol "tx-origin"
generate_expected_json tests/unused_state.sol "unused-state"
generate_expected_json tests/locked_ether.sol "locked-ether"
generate_expected_json tests/arbitrary_send.sol "arbitrary-send"
generate_expected_json tests/inline_assembly_contract.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/const_state_variables.sol "constable-states"
generate_expected_json tests/external_function.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/uninitialized_local_variable.sol "uninitialized-local"
generate_expected_json tests/controlled_delegatecall.sol "controlled-delegatecall"
generate_expected_json tests/constant.sol "constant-function"
generate_expected_json tests/unused_return.sol "unused-return"
generate_expected_json tests/shadowing_state_variable.sol "shadowing-state"
generate_expected_json tests/shadowing_abstract.sol "shadowing-abstract"
generate_expected_json tests/timestamp.sol "timestamp"
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_local_variable.sol "shadowing-local"
generate_expected_json tests/solc_version_incorrect.sol "solc-version"
generate_expected_json tests/right_to_left_override.sol "rtlo"
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
}
#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/backdoor.sol "backdoor"
#generate_expected_json tests/backdoor.sol "suicidal"
#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/tx_origin-0.5.1.sol "tx-origin"
#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/inline_assembly_contract-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/incorrect_equality.sol "incorrect-equality"
#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_send-0.5.1.sol "unchecked-send"
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/backdoor.sol "backdoor"
generate_expected_json tests/backdoor.sol "suicidal"
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/tx_origin-0.5.1.sol "tx-origin"
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/inline_assembly_contract-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/incorrect_equality.sol "incorrect-equality"
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_send-0.5.1.sol "unchecked-send"

@ -24,5 +24,3 @@ function 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/complex_func.sol "complex-function"
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/unused_return.sol "unused-return"
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_2.sol "external-function"
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/constant-0.5.1.sol "constant-function"
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")
if [ "$DIFF" != "" ]
then
echo "slither-check-upgradeability failed"
echo "slither-check-upgradeability 1 failed"
cat test_1.txt
echo ""
cat "$DIR_TESTS/test_1.txt"
exit -1
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")
if [ "$DIFF" != "" ]
then
echo "slither-check-upgradeability failed"
echo "slither-check-upgradeability 2 failed"
cat test_2.txt
echo ""
cat "$DIR_TESTS/test_2.txt"
exit -1
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")
if [ "$DIFF" != "" ]
then
echo "slither-check-upgradeability failed"
echo "slither-check-upgradeability 3 failed"
cat test_3.txt
echo ""
cat "$DIR_TESTS/test_3.txt"
exit -1
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")
if [ "$DIFF" != "" ]
then
echo "slither-check-upgradeability failed"
echo "slither-check-upgradeability 4 failed"
cat test_4.txt
echo ""
cat "$DIR_TESTS/test_4.txt"
exit -1
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")
if [ "$DIFF" != "" ]
then
echo "slither-check-upgradeability failed"
echo "slither-check-upgradeability 5 failed"
cat test_5.txt
echo ""
cat "$DIR_TESTS/test_5.txt"
echo ""
echo "$DIFF"
exit -1
fi

@ -11,3 +11,4 @@ class ChildContract:
@property
def contract(self):
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._modifiers = {}
self._functions = {}
self._using_for = {}
self._kind = None
@ -77,6 +78,20 @@ class Contract(ChildSlither, SourceMapping):
'''
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):
return self._structures
@ -91,6 +106,20 @@ class Contract(ChildSlither, SourceMapping):
def enums(self):
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):
return self._enums
@ -108,6 +137,20 @@ class Contract(ChildSlither, SourceMapping):
'''
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):
return self._events
@ -153,6 +196,20 @@ class Contract(ChildSlither, SourceMapping):
'''
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
def slithir_variables(self):
'''
@ -177,18 +234,18 @@ class Contract(ChildSlither, SourceMapping):
executed, following the c3 linearization
Return None if there is no constructor.
'''
cst = self.constructor_not_inherited
cst = self.constructors_declared
if cst:
return cst
for inherited_contract in self.inheritance:
cst = inherited_contract.constructor_not_inherited
cst = inherited_contract.constructors_declared
if cst:
return cst
return None
@property
def constructor_not_inherited(self):
return next((func for func in self.functions if func.is_constructor and func.contract == self), None)
def constructors_declared(self):
return next((func for func in self.functions if func.is_constructor and func.contract_declarer == self), None)
@property
def constructors(self):
@ -238,29 +295,29 @@ class Contract(ChildSlither, SourceMapping):
'''
return list(self._functions.values())
def functions_as_dict(self):
return self._functions
def available_functions_as_dict(self):
return {f.full_name: f for f in self._functions.values() if not f.is_shadowed}
@property
def functions_inherited(self):
'''
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
def functions_not_inherited(self):
def functions_declared(self):
'''
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
def functions_entry_points(self):
'''
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
def modifiers(self):
@ -269,22 +326,22 @@ class Contract(ChildSlither, SourceMapping):
'''
return list(self._modifiers.values())
def modifiers_as_dict(self):
return self._modifiers
def available_modifiers_as_dict(self):
return {m.full_name: m for m in self._modifiers.values() if not m.is_shadowed}
@property
def modifiers_inherited(self):
'''
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
def modifiers_not_inherited(self):
def modifiers_declared(self):
'''
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
def functions_and_modifiers(self):
@ -301,11 +358,36 @@ class Contract(ChildSlither, SourceMapping):
return self.functions_inherited + self.modifiers_inherited
@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)
'''
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
###################################################################################
@ -375,7 +457,7 @@ class Contract(ChildSlither, SourceMapping):
Returns:
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):
"""
@ -385,7 +467,28 @@ class Contract(ChildSlither, SourceMapping):
Returns:
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):
"""
@ -456,7 +559,7 @@ class Contract(ChildSlither, SourceMapping):
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]
return [f for f in candidates if f.full_name == function.full_name]
@ -470,10 +573,12 @@ class Contract(ChildSlither, SourceMapping):
@property
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 = [item for sublist in all_calls for item in sublist] + self.functions
all_calls = [f for f in self.functions + self.modifiers if not f.is_shadowed]
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_constructors = [c.constructor for c in self.inheritance]

@ -19,5 +19,13 @@ class Enum(ChildContract, SourceMapping):
def values(self):
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):
return self.name

@ -29,9 +29,25 @@ class Event(ChildContract, SourceMapping):
name, parameters = self.signature
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
def elems(self):
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):
return self.name

@ -6,6 +6,7 @@ from collections import namedtuple
from itertools import groupby
from slither.core.children.child_contract import ChildContract
from slither.core.children.child_inheritance import ChildInheritance
from slither.core.declarations.solidity_variables import (SolidityFunction,
SolidityVariable,
SolidityVariableComposed)
@ -18,7 +19,7 @@ logger = logging.getLogger("Function")
ReacheableNode = namedtuple('ReacheableNode', ['node', 'ir'])
class Function(ChildContract, SourceMapping):
class Function(ChildContract, ChildInheritance, SourceMapping):
"""
Function class
"""
@ -84,6 +85,8 @@ class Function(ChildContract, SourceMapping):
self._all_conditional_solidity_variables_read_with_loop = None
self._all_solidity_variables_used_as_args = None
self._is_shadowed = False
# set(ReacheableNode)
self._reachable_from_nodes = set()
self._reachable_from_functions = set()
@ -116,12 +119,21 @@ class Function(ChildContract, SourceMapping):
name, parameters, _ = self.signature
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
def is_constructor(self):
"""
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
def contains_assembly(self):
@ -131,6 +143,14 @@ class Function(ChildContract, SourceMapping):
def slither(self):
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
###################################################################################
###################################################################################
@ -173,6 +193,14 @@ class Function(ChildContract, SourceMapping):
"""
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
###################################################################################
###################################################################################
@ -307,7 +335,7 @@ class Function(ChildContract, SourceMapping):
included.
"""
# 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
@ -560,7 +588,7 @@ class Function(ChildContract, SourceMapping):
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]
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);
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.state_variables_read + self.solidity_variables_read],
[str(x) for x in self.state_variables_written],

@ -25,6 +25,15 @@ class Structure(ChildContract, SourceMapping):
def elems(self):
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
def elems_ordered(self):
ret = []
@ -32,5 +41,6 @@ class Structure(ChildContract, SourceMapping):
ret.append(self._elems[e])
return ret
def __str__(self):
return self.name

@ -50,3 +50,8 @@ class LocalVariable(ChildFunction, Variable):
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):
def is_declared_by(self, contract):
"""
Check if the element is declared by the contract
:param contract:
:return:
"""
return self.contract == contract
###################################################################################
###################################################################################
# region Signature
@ -36,7 +46,7 @@ class StateVariable(ChildContract, Variable):
@property
def canonical_name(self):
return '{}:{}'.format(self.contract.name, self.name)
return '{}.{}'.format(self.contract.name, self.name)
@property
def full_name(self):
@ -51,3 +61,4 @@ class StateVariable(ChildContract, Variable):
# endregion
###################################################################################
###################################################################################

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

@ -160,7 +160,13 @@ class AbstractDetector(metaclass=abc.ABCMeta):
def _create_parent_element(element):
from slither.core.children.child_contract import ChildContract
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:
contract = {'elements': []}
AbstractDetector.add_contract_to_json(element.contract, contract)
@ -211,10 +217,11 @@ class AbstractDetector(metaclass=abc.ABCMeta):
additional_fields)
d['elements'].append(element)
@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):
AbstractDetector.add_function_to_json(function, d)
AbstractDetector.add_function_to_json(function, d, additional_fields)
@staticmethod
def add_enum_to_json(enum, d, additional_fields={}):
@ -267,6 +274,7 @@ class AbstractDetector(metaclass=abc.ABCMeta):
additional_fields)
d['elements'].append(element)
@staticmethod
def add_nodes_to_json(nodes, d):
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 = []
for c in self.contracts:
for f in c.functions:
if f.contract != c:
if f.contract_declarer != c:
continue
if f.view or f.pure:
if f.contains_assembly:
attr = 'view' if f.view else 'pure'
info = '{}.{} ({}) is declared {} but contains assembly code\n'
info = info.format(f.contract.name, f.name, f.source_mapping_str, attr)
info = '{} ({}) is declared {} but contains assembly code\n'
info = info.format(f.canonical_name, f.source_mapping_str, attr)
json = self.generate_json_result(info, {'contains_assembly': True})
self.add_function_to_json(f, 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()
if variables_written:
attr = 'view' if f.view else 'pure'
info = '{}.{} ({}) is declared {} but changes state variables:\n'
info = info.format(f.contract.name, f.name, f.source_mapping_str, attr)
info = '{} ({}) is declared {} but changes state variables:\n'
info = info.format(f.canonical_name, f.source_mapping_str, attr)
for variable_written in variables_written:
info += '\t- {}.{}\n'.format(variable_written.contract.name,
variable_written.name)
info += '\t- {}\n'.format(variable_written.canonical_name)
json = self.generate_json_result(info, {'contains_assembly': False})
self.add_function_to_json(f, json)

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

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

@ -47,11 +47,7 @@ In this case, Transfer and Approval events should have the 'indexed' keyword on
return results
# Loop through all events to look for poor form.
for event in contract.events:
# Only handle events which are declared in this contract.
if event.contract != contract:
continue
for event in contract.events_declared:
# If this is transfer/approval events, expect the first two parameters to be indexed.
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:
# Add each problematic event definition to our result list
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)
# 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)
return results

@ -94,7 +94,7 @@ Bob calls `setDestination` and `withdraw`. As a result he withdraws the contract
list((Function), (list (Node)))
"""
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)
if 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)
for (func, nodes) in arbitrary_send:
info = "{}.{} ({}) sends eth to arbitrary user\n"
info = info.format(func.contract.name,
func.name,
info = "{} ({}) sends eth to arbitrary user\n"
info = info.format(func.canonical_name,
func.source_mapping_str)
info += '\tDangerous calls:\n'
for node in nodes:

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

@ -71,7 +71,7 @@ class ExternalFunction(AbstractDetector):
for contract in function.contract.inheritance + [function.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 f.full_name == function.full_name:
@ -120,7 +120,7 @@ class ExternalFunction(AbstractDetector):
continue
# 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 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.
for function_definition in all_function_definitions:
txt = "{}.{} ({}) should be declared external\n"
info = txt.format(function_definition.contract.name,
function_definition.name,
txt = "{} ({}) should be declared external\n"
info = txt.format(function_definition.canonical_name,
function_definition.source_mapping_str)
json = self.generate_json_result(info)

@ -59,7 +59,7 @@ Bob calls `kill` and destructs the contract.'''
def detect_suicidal(self, contract):
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):
ret.append(f)
return ret
@ -72,9 +72,8 @@ Bob calls `kill` and destructs the contract.'''
functions = self.detect_suicidal(c)
for func in functions:
txt = "{}.{} ({}) allows anyone to destruct the contract\n"
info = txt.format(func.contract.name,
func.name,
txt = "{} ({}) allows anyone to destruct the contract\n"
info = txt.format(func.canonical_name,
func.source_mapping_str)
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)
for struct in contract.structures:
if struct.contract != contract:
continue
for struct in contract.structures_declared:
if not self.is_cap_words(struct.name):
info = "Struct '{}.{}' ({}) is not in CapWords\n"
info = info.format(struct.contract.name, struct.name, struct.source_mapping_str)
info = "Struct '{}' ({}) is not in CapWords\n"
info = info.format(struct.canonical_name, struct.source_mapping_str)
json = self.generate_json_result(info)
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)
for event in contract.events:
if event.contract != contract:
continue
for event in contract.events_declared:
if not self.is_cap_words(event.name):
info = "Event '{}.{}' ({}) is not in CapWords\n"
info = info.format(event.contract.name, event.name, event.source_mapping_str)
info = "Event '{}' ({}) is not in CapWords\n"
info = info.format(event.canonical_name, event.source_mapping_str)
json = self.generate_json_result(info)
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)
for func in contract.functions:
if func.contract != contract:
continue
for func in contract.functions_declared:
if not self.is_mixed_case(func.name):
info = "Function '{}.{}' ({}) is not in mixedCase\n"
info = info.format(func.contract.name, func.name, func.source_mapping_str)
info = "Function '{}' ({}) is not in mixedCase\n"
info = info.format(func.canonical_name, func.source_mapping_str)
json = self.generate_json_result(info)
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:
correct_naming = self.is_mixed_case_with_underscore(argument.name)
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,
argument.function.contract.name,
argument.function,
argument.canonical_name,
argument.source_mapping_str)
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)
for var in contract.state_variables:
if var.contract != contract:
continue
for var in contract.state_variables_declared:
if self.should_avoid_name(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 = info.format(var.contract.name, var.name, var.source_mapping_str)
info = "Variable '{}' ({}) used l, O, I, which should not be used\n"
info = info.format(var.canonical_name, var.source_mapping_str)
json = self.generate_json_result(info)
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
if not self.is_upper_case_with_underscores(var.name):
info = "Constant '{}.{}' ({}) is not in UPPER_CASE_WITH_UNDERSCORES\n"
info = info.format(var.contract.name, var.name, var.source_mapping_str)
info = "Constant '{}' ({}) is not in UPPER_CASE_WITH_UNDERSCORES\n"
info = info.format(var.canonical_name, var.source_mapping_str)
json = self.generate_json_result(info)
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:
correct_naming = self.is_mixed_case(var.name)
if not correct_naming:
info = "Variable '{}.{}' ({}) is not in mixedCase\n"
info = info.format(var.contract.name, var.name, var.source_mapping_str)
info = "Variable '{}' ({}) is not in mixedCase\n"
info = info.format(var.canonical_name, var.source_mapping_str)
json = self.generate_json_result(info)
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)
for enum in contract.enums:
if enum.contract != contract:
continue
for enum in contract.enums_declared:
if not self.is_cap_words(enum.name):
info = "Enum '{}.{}' ({}) is not in CapWords\n"
info = info.format(enum.contract.name, enum.name, enum.source_mapping_str)
info = "Enum '{}' ({}) is not in CapWords\n"
info = info.format(enum.canonical_name, enum.source_mapping_str)
json = self.generate_json_result(info)
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)
for modifier in contract.modifiers:
if modifier.contract != contract:
continue
for modifier in contract.modifiers_declared:
if not self.is_mixed_case(modifier.name):
info = "Modifier '{}.{}' ({}) is not in mixedCase\n"
info = info.format(modifier.contract.name,
modifier.name,
info = "Modifier '{}' ({}) is not in mixedCase\n"
info = info.format(modifier.canonical_name,
modifier.source_mapping_str)
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)
return results

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

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

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

@ -181,7 +181,7 @@ class Reentrancy(AbstractDetector):
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 self.KEY in function.context:
continue

@ -45,7 +45,7 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
def find_reentrancies(self):
result = {}
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:
# dead code
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:
calls = sorted(list(set(calls)), key=lambda x: x.node_id)
send_eth = sorted(list(set(send_eth)), key=lambda x: x.node_id)
info = 'Reentrancy in {}.{} ({}):\n'
info = info.format(func.contract.name, func.name, func.source_mapping_str)
info = 'Reentrancy in {} ({}):\n'
info = info.format(func.canonical_name, func.source_mapping_str)
info += '\tExternal calls:\n'
for call_info in calls:
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):
result = {}
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:
# dead code
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)
send_eth = sorted(list(set(send_eth)), key=lambda x: x.node_id)
info = 'Reentrancy in {}.{} ({}):\n'
info = info.format(func.contract.name, func.name, func.source_mapping_str)
info = 'Reentrancy in {} ({}):\n'
info = info.format(func.canonical_name, func.source_mapping_str)
info += '\tExternal calls:\n'
for call_info in calls:
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):
result = {}
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:
# dead code
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)
for (func, calls), varsWritten in result_sorted:
calls = sorted(list(set(calls)), key=lambda x: x.node_id)
info = 'Reentrancy in {}.{} ({}):\n'
info = info.format(func.contract.name, func.name, func.source_mapping_str)
info = 'Reentrancy in {} ({}):\n'
info = info.format(func.canonical_name, func.source_mapping_str)
info += '\tExternal calls:\n'
for call_info in calls:
info += '\t- {} ({})\n'.format(call_info.expression, call_info.source_mapping_str)

@ -41,9 +41,9 @@ contract DerivedContract is BaseContract{
variables_fathers = []
for father in contract.inheritance:
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]
if shadow:
ret.append([var] + shadow)
@ -65,12 +65,10 @@ contract DerivedContract is BaseContract{
for all_variables in shadowing:
shadow = all_variables[0]
variables = all_variables[1:]
info = '{}.{} ({}) shadows:\n'.format(shadow.contract.name,
shadow.name,
shadow.source_mapping_str)
info = '{} ({}) shadows:\n'.format(shadow.canonical_name,
shadow.source_mapping_str)
for var in variables:
info += "\t- {}.{} ({})\n".format(var.contract.name,
var.name,
info += "\t- {} ({})\n".format(var.canonical_name,
var.source_mapping_str)
json = self.generate_json_result(info)

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

@ -58,7 +58,7 @@ contract Bug {
# Loop through all functions + modifiers in this contract.
for function in contract.functions + contract.modifiers:
# 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
# This function was declared in this contract, we check what its local variables might shadow.
@ -66,20 +66,20 @@ contract Bug {
overshadowed = []
for scope_contract in [contract] + contract.inheritance:
# Check functions
for scope_function in scope_contract.functions:
if variable.name == scope_function.name and scope_function.contract == scope_contract:
for scope_function in scope_contract.functions_declared:
if variable.name == scope_function.name:
overshadowed.append((self.OVERSHADOWED_FUNCTION, scope_contract.name, scope_function))
# Check modifiers
for scope_modifier in scope_contract.modifiers:
if variable.name == scope_modifier.name and scope_modifier.contract == scope_contract:
for scope_modifier in scope_contract.modifiers_declared:
if variable.name == scope_modifier.name:
overshadowed.append((self.OVERSHADOWED_MODIFIER, scope_contract.name, scope_modifier))
# Check events
for scope_event in scope_contract.events:
if variable.name == scope_event.name and scope_event.contract == scope_contract:
for scope_event in scope_contract.events_declared:
if variable.name == scope_event.name:
overshadowed.append((self.OVERSHADOWED_EVENT, scope_contract.name, scope_event))
# Check state variables
for scope_state_variable in scope_contract.variables:
if variable.name == scope_state_variable.name and scope_state_variable.contract == scope_contract:
for scope_state_variable in scope_contract.state_variables_declared:
if variable.name == scope_state_variable.name:
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.

@ -53,9 +53,9 @@ contract DerivedContract is BaseContract{
variables_fathers = []
for father in contract.inheritance:
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]
if shadow:
ret.append([var] + shadow)
@ -76,13 +76,11 @@ contract DerivedContract is BaseContract{
for all_variables in shadowing:
shadow = all_variables[0]
variables = all_variables[1:]
info = '{}.{} ({}) shadows:\n'.format(shadow.contract.name,
shadow.name,
shadow.source_mapping_str)
info = '{} ({}) shadows:\n'.format(shadow.canonical_name,
shadow.source_mapping_str)
for var in variables:
info += "\t- {}.{} ({})\n".format(var.contract.name,
var.name,
var.source_mapping_str)
info += "\t- {} ({})\n".format(var.canonical_name,
var.source_mapping_str)
json = self.generate_json_result(info)
self.add_variables_to_json(all_variables, json)

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

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

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

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

@ -86,11 +86,11 @@ class ConstCandidateStateVars(AbstractDetector):
# Create a result for each finding
for v in constable_variables:
info = "{}.{} should be constant ({})\n".format(v.contract.name,
v.name,
v.source_mapping_str)
info = "{} should be constant ({})\n".format(v.canonical_name,
v.source_mapping_str)
json = self.generate_json_result(info)
self.add_variable_to_json(v, json)
results.append(json)
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 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:
continue
# 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:
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,
function.contract.name,
function.name,
function.canonical_name,
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:
ret = self.detect_uninitialized(c)
for variable, functions in ret:
info = "{}.{} ({}) is never initialized. It is used in:\n"
info = info.format(variable.contract.name,
variable.name,
info = "{} ({}) is never initialized. It is used in:\n"
info = info.format(variable.canonical_name,
variable.source_mapping_str)
for f in functions:
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:
var_name = uninitialized_storage_variable.name
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 = "{} in {} ({}) is a storage variable never initialiazed\n"
info = info.format(var_name, function.canonical_name, uninitialized_storage_variable.source_mapping_str)
json = self.generate_json_result(info)

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

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

@ -35,7 +35,7 @@ class DataDependency(AbstractPrinter):
txt += str(table)
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
table = PrettyTable(['Variable', 'Dependencies'])
for v in f.variables:

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

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

@ -104,6 +104,21 @@ def get_sig(ir, name):
argss = convert_arguments(ir.arguments)
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):
argss = [[]]
for arg in arguments:
@ -399,7 +414,7 @@ def propagate_types(ir, node):
elif isinstance(ir, InternalCall):
# if its not a tuple, return a singleton
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
if return_type:
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 ins.ori.variable_left in contract.inheritance + [contract]:
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
return internalcall
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
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
if t in using_for:
@ -759,14 +777,25 @@ def convert_type_library_call(ir, lib_contract):
def convert_type_of_high_and_internal_level_call(ir, contract):
func = None
sigs = get_sig(ir, ir.function_name)
for sig in sigs:
func = contract.get_function_from_signature(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
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)
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
if not func:
# specific lookup when the compiler does implicit conversion
# for example

@ -1,21 +1,20 @@
from slither.core.declarations.function import Function
from slither.slithir.operations.call import Call
from slither.slithir.operations.lvalue import OperationWithLValue
from slither.core.variables.variable import Variable
from slither.slithir.variables import Constant
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__()
if isinstance(function, Function):
self._function = function
self._function_name = function.name
self._contract_name = function.contract_declarer.name
else:
isinstance(function, Constant)
self._function = None
self._function_name = function
self._contract = contract
self._function_name, self._contract_name = function
#self._contract = contract
self._nbr_arguments = nbr_arguments
self._type_call = type_call
self._lvalue = result
@ -32,14 +31,14 @@ class InternalCall(Call, OperationWithLValue):
def function(self, f):
self._function = f
@property
def contract(self):
return self._contract
@property
def function_name(self):
return self._function_name
@property
def contract_name(self):
return self._contract_name
@property
def nbr_arguments(self):
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))
else:
lvalue = '{}({}) = '.format(self.lvalue, self.lvalue.type)
txt = '{}INTERNAL_CALL, {}.{}({})'
txt = '{}INTERNAL_CALL, {}({})'
return txt.format(lvalue,
self.function.contract.name,
self.function.full_name,
self.function.canonical_name,
','.join(args))

@ -566,7 +566,7 @@ def copy_ir(ir, *instances):
nbr_arguments = ir.nbr_arguments
lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
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)
return new_ir
elif isinstance(ir, InternalDynamicCall):

@ -232,8 +232,9 @@ class ContractSolc04(Contract):
def _parse_modifier(self, modifier):
modif = ModifierSolc(modifier, self)
modif = ModifierSolc(modifier, self, self)
modif.set_contract(self)
modif.set_contract_declarer(self)
modif.set_offset(modifier['src'], self.slither)
self.slither.add_modifier(modif)
self._modifiers_no_params.append(modif)
@ -247,7 +248,7 @@ class ContractSolc04(Contract):
return
def _parse_function(self, function):
func = FunctionSolc(function, self)
func = FunctionSolc(function, self, self)
func.set_offset(function['src'], self.slither)
self.slither.add_function(func)
self._functions_no_params.append(func)
@ -281,26 +282,52 @@ class ContractSolc04(Contract):
return
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:
modifier.analyze_params()
self._modifiers[modifier.full_name] = modifier
elements_no_params = self._modifiers_no_params
getter = lambda f: f.modifiers
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 = []
return
def analyze_params_functions(self):
# 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
contracts_visited = []
for father in self.inheritance_reverse:
functions = {k:v for (k, v) in father.functions_as_dict().items()
if not v.contract in contracts_visited}
contracts_visited.append(father)
self._functions.update(functions)
elements_no_params = self._functions_no_params
getter = lambda f: f.functions
getter_available = lambda f: f.available_functions_as_dict().items()
Cls = FunctionSolc
self._functions = self._analyze_params_elements(elements_no_params, getter, getter_available, Cls)
self._functions_no_params = []
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
# We remove the previous constructor
@ -308,20 +335,25 @@ class ContractSolc04(Contract):
#
# Note: contract.all_functions_called returns the constructors of the base contracts
has_constructor = False
for function in self._functions_no_params:
function.analyze_params()
if function.is_constructor:
for element in elements_no_params:
element.analyze_params()
if element.is_constructor:
has_constructor = True
if has_constructor:
_functions = {k:v for (k, v) in self._functions.items() if not v.is_constructor}
self._functions = _functions
_accessible_functions = {k: v for (k, v) in accessible_elements.items() if not v.is_constructor}
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):
from slither.solc_parsing.expressions.expression_parsing import VariableNotFound
@ -434,17 +466,15 @@ class ContractSolc04(Contract):
def convert_expression_to_slithir(self):
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()
for contract in self.inheritance:
for v in contract.variables:
if v.contract == contract:
new_var = StateIRVariable(v)
all_ssa_state_variables_instances[v.canonical_name] = new_var
self._initial_state_variables.append(new_var)
for v in contract.state_variables_declared:
new_var = StateIRVariable(v)
all_ssa_state_variables_instances[v.canonical_name] = new_var
self._initial_state_variables.append(new_var)
for v in self.variables:
if v.contract == self:
@ -453,8 +483,7 @@ class ContractSolc04(Contract):
self._initial_state_variables.append(new_var)
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):
last_state_variables_instances = dict()

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

@ -60,15 +60,31 @@ def get_pointer_name(variable):
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):
function = None
contract = caller_context
contract_declarer = caller_context
elif isinstance(caller_context, Function):
function = caller_context
contract = function.contract
contract_declarer = function.contract_declarer
else:
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:
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:
return contract_variables[var_name]
# 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:
return conc_variables_ptr[var_name]
functions = contract.functions_as_dict()
if is_super:
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:
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:
return modifiers[var_name]
# structures are looked on the contract declarer
structures = contract.structures_as_dict()
if var_name in structures:
return structures[var_name]
@ -530,6 +557,7 @@ def parse_expression(expression, caller_context):
referenced_declaration = expression['referencedDeclaration']
else:
referenced_declaration = None
var = find_variable(value, caller_context, referenced_declaration)
identifier = Identifier(var)
@ -571,18 +599,7 @@ def parse_expression(expression, caller_context):
member_expression = parse_expression(children[0], caller_context)
if str(member_expression) == 'super':
super_name = parse_super_name(expression, is_compact_ast)
if isinstance(caller_context, Contract):
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
var = find_variable(super_name, caller_context, is_super=True)
if var is None:
raise VariableNotFound('Variable not found: {}'.format(super_name))
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]
var_type = next((e for e in all_enums if e.name == enum_name), None)
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:
# any contract can refer to another contract's structure
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]
var_type = next((st for st in all_structures if st.name == name_struct), None)
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
if not var_type:
depth = 0
while name_struct.endswith('[]'):
name_struct = name_struct[0:-2]
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:
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):
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 function1.full_name in results or function1.is_constructor or not function1.is_implemented:
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).
-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 = {}
for base_contract in reversed(contract.immediate_inheritance):
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)):
# 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.
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],
colliding_functions[x][0], colliding_functions[x][1]))
@ -128,8 +128,7 @@ def detect_state_variable_shadowing(contracts):
"""
results = set()
for contract in contracts:
variables_declared = {variable.name: variable for variable in contract.variables
if variable.contract == contract}
variables_declared = {variable.name: variable for variable in contract.state_variables_declared}
for immediate_base_contract in contract.immediate_inheritance:
for variable in immediate_base_contract.variables:
if variable.name in variables_declared:

@ -129,7 +129,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
val = TupleVariable(self._node)
else:
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)
set_val(expression, val)
else:

@ -1,6 +1,6 @@
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:Missing call to Contract_no_bug.initialize in Contract_not_called_super_init
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: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:
Contract_no_bug needs to be initialized by initialize()

@ -7,7 +7,7 @@
"check": "arbitrary-send",
"impact": "High",
"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": [
{
"type": "function",
@ -192,7 +192,7 @@
"check": "arbitrary-send",
"impact": "High",
"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": [
{
"type": "function",

@ -1,8 +1,8 @@
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:
- 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:
- 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

@ -7,7 +7,7 @@
"check": "arbitrary-send",
"impact": "High",
"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": [
{
"type": "function",
@ -192,7 +192,7 @@
"check": "arbitrary-send",
"impact": "High",
"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": [
{
"type": "function",

@ -1,8 +1,8 @@
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:
- 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:
- 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

@ -7,7 +7,7 @@
"check": "suicidal",
"impact": "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": [
{
"type": "function",

@ -1,5 +1,5 @@
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
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

@ -7,7 +7,7 @@
"check": "constant-function",
"impact": "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": [
{
"type": "function",

@ -1,4 +1,4 @@
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
INFO:Slither:tests/constant-0.5.1.sol analyzed (1 contracts), 1 result(s) found

@ -7,7 +7,7 @@
"check": "constant-function",
"impact": "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": [
{
"type": "function",
@ -141,7 +141,7 @@
"check": "constant-function",
"impact": "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": [
{
"type": "function",
@ -275,7 +275,7 @@
"check": "constant-function",
"impact": "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": [
{
"type": "function",

@ -1,8 +1,8 @@
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.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.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
INFO:Slither:tests/constant.sol analyzed (1 contracts), 3 result(s) found

@ -7,7 +7,7 @@
"check": "external-function",
"impact": "Informational",
"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": [
{
"type": "function",
@ -72,7 +72,7 @@
"check": "external-function",
"impact": "Informational",
"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": [
{
"type": "function",
@ -137,7 +137,7 @@
"check": "external-function",
"impact": "Informational",
"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": [
{
"type": "function",
@ -202,7 +202,7 @@
"check": "external-function",
"impact": "Informational",
"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": [
{
"type": "function",

@ -1,7 +1,7 @@
INFO:Detectors:
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.funcNotCalled (tests/external_function.sol#21-23) should be declared external
ContractWithFunctionNotCalled2.funcNotCalled (tests/external_function.sol#32-39) 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.funcNotCalled() (tests/external_function.sol#21-23) 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
INFO:Slither:tests/external_function.sol analyzed (5 contracts), 4 result(s) found

@ -7,7 +7,7 @@
"check": "incorrect-equality",
"impact": "Medium",
"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": [
{
"type": "node",
@ -148,7 +148,7 @@
"check": "incorrect-equality",
"impact": "Medium",
"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": [
{
"type": "node",
@ -289,7 +289,7 @@
"check": "incorrect-equality",
"impact": "Medium",
"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": [
{
"type": "node",
@ -530,7 +530,7 @@
"check": "incorrect-equality",
"impact": "Medium",
"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": [
{
"type": "node",
@ -771,7 +771,7 @@
"check": "incorrect-equality",
"impact": "Medium",
"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": [
{
"type": "node",
@ -1012,7 +1012,7 @@
"check": "incorrect-equality",
"impact": "Medium",
"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": [
{
"type": "node",
@ -1253,7 +1253,7 @@
"check": "incorrect-equality",
"impact": "Medium",
"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": [
{
"type": "node",
@ -1500,7 +1500,7 @@
"check": "incorrect-equality",
"impact": "Medium",
"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": [
{
"type": "node",
@ -1747,7 +1747,7 @@
"check": "incorrect-equality",
"impact": "Medium",
"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": [
{
"type": "node",
@ -1994,7 +1994,7 @@
"check": "incorrect-equality",
"impact": "Medium",
"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": [
{
"type": "node",
@ -2171,7 +2171,7 @@
"check": "incorrect-equality",
"impact": "Medium",
"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": [
{
"type": "node",
@ -2348,7 +2348,7 @@
"check": "incorrect-equality",
"impact": "Medium",
"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": [
{
"type": "node",

@ -1,27 +1,27 @@
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)
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)
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)
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)
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)
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)
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
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
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
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)
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)
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)
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

@ -7,7 +7,7 @@
"check": "erc20-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -59,7 +59,7 @@
"check": "erc20-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -111,7 +111,7 @@
"check": "erc20-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -163,7 +163,7 @@
"check": "erc20-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -215,7 +215,7 @@
"check": "erc20-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -267,7 +267,7 @@
"check": "erc20-interface",
"impact": "Medium",
"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": [
{
"type": "function",

@ -1,9 +1,9 @@
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: approve (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: 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: allowance (tests/incorrect_erc20_interface.sol#9)
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(address,uint256) (tests/incorrect_erc20_interface.sol#5)
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: balanceOf(address) (tests/incorrect_erc20_interface.sol#8)
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
INFO:Slither:tests/incorrect_erc20_interface.sol analyzed (1 contracts), 6 result(s) found

@ -7,7 +7,7 @@
"check": "erc721-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -54,7 +54,7 @@
"check": "erc721-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -109,7 +109,7 @@
"check": "erc721-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -164,7 +164,7 @@
"check": "erc721-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -219,7 +219,7 @@
"check": "erc721-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -274,7 +274,7 @@
"check": "erc721-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -329,7 +329,7 @@
"check": "erc721-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -384,7 +384,7 @@
"check": "erc721-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -439,7 +439,7 @@
"check": "erc721-interface",
"impact": "Medium",
"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": [
{
"type": "function",
@ -494,7 +494,7 @@
"check": "erc721-interface",
"impact": "Medium",
"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": [
{
"type": "function",

@ -1,13 +1,13 @@
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: balanceOf (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: safeTransferFrom (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: transferFrom (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: setApprovalForAll (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: isApprovedForAll (tests/incorrect_erc721_interface.sol#15)
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(address) (tests/incorrect_erc721_interface.sol#7)
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(address,address,uint256,bytes) (tests/incorrect_erc721_interface.sol#9)
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(address,address,uint256) (tests/incorrect_erc721_interface.sol#11)
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(address,bool) (tests/incorrect_erc721_interface.sol#13)
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(address,address) (tests/incorrect_erc721_interface.sol#15)
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

@ -7,7 +7,7 @@
"check": "assembly",
"impact": "Informational",
"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": [
{
"type": "function",

@ -1,5 +1,5 @@
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
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

@ -7,7 +7,7 @@
"check": "assembly",
"impact": "Informational",
"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": [
{
"type": "function",

@ -1,5 +1,5 @@
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
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

@ -7,7 +7,7 @@
"check": "assembly",
"impact": "Informational",
"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": [
{
"type": "function",
@ -209,7 +209,7 @@
"check": "assembly",
"impact": "Informational",
"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": [
{
"type": "function",

@ -1,7 +1,7 @@
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
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
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

@ -7,7 +7,7 @@
"check": "assembly",
"impact": "Informational",
"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": [
{
"type": "function",
@ -209,7 +209,7 @@
"check": "assembly",
"impact": "Informational",
"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": [
{
"type": "function",

@ -1,7 +1,7 @@
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
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
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

@ -7,7 +7,7 @@
"check": "low-level-calls",
"impact": "Informational",
"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": [
{
"type": "function",

@ -1,5 +1,5 @@
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
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

@ -7,7 +7,7 @@
"check": "calls-loop",
"impact": "Low",
"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": [
{
"type": "node",

@ -1,4 +1,4 @@
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
INFO:Slither:tests/multiple_calls_in_loop.sol analyzed (1 contracts), 1 result(s) found

@ -176,7 +176,7 @@
"check": "naming-convention",
"impact": "Informational",
"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": [
{
"type": "event",
@ -270,7 +270,7 @@
"check": "naming-convention",
"impact": "Informational",
"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": [
{
"type": "function",
@ -367,7 +367,7 @@
"check": "naming-convention",
"impact": "Informational",
"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": [
{
"type": "variable",
@ -762,7 +762,7 @@
"check": "naming-convention",
"impact": "Informational",
"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": [
{
"type": "function",
@ -858,7 +858,7 @@
"check": "naming-convention",
"impact": "Informational",
"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": [
{
"type": "variable",

@ -1,14 +1,14 @@
INFO:Detectors:
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
Event 'naming.event_' (tests/naming_convention.sol#23) is not in CapWords
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
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
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
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
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
Modifier 'naming.CantDo()' (tests/naming_convention.sol#41-43) 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.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

@ -1,5 +1,5 @@
INFO:Detectors:
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:tests/old_solc.sol.json analyzed (1 contracts), 1 result(s) found

@ -7,7 +7,7 @@
"check": "reentrancy-eth",
"impact": "High",
"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": [
{
"type": "function",
@ -348,7 +348,7 @@
"check": "reentrancy-eth",
"impact": "High",
"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": [
{
"type": "function",

@ -1,10 +1,10 @@
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:
- (ret,mem) = msg.sender.call.value(userBalance[msg.sender])() (tests/reentrancy-0.5.1.sol#17)
State variables written after the call(s):
- 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:
- (ret,mem) = msg.sender.call.value(amount)() (tests/reentrancy-0.5.1.sol#49)
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