Merges with dev. Supports most recent changes to detector json output.

pull/238/head
rajeevgopalakrishna 6 years ago
commit fda131811e
  1. 1
      .travis.yml
  2. 2
      README.md
  3. 2
      examples/scripts/functions_called.py
  4. 8
      examples/scripts/possible_paths.py
  5. 2
      examples/scripts/slithIR.py
  6. 70
      scripts/tests_generate_expected_json_4.sh
  7. 31
      scripts/tests_generate_expected_json_5.sh
  8. 2
      scripts/travis_install.sh
  9. 1
      scripts/travis_test_4.sh
  10. 3
      scripts/travis_test_5.sh
  11. 2
      scripts/travis_test_etherscan.sh
  12. 21
      scripts/travis_test_simil.sh
  13. 17
      scripts/travis_test_upgradability.sh
  14. 7
      setup.py
  15. 20
      slither/__main__.py
  16. 2
      slither/all_exceptions.py
  17. 8
      slither/core/cfg/node.py
  18. 1
      slither/core/children/child_contract.py
  19. 13
      slither/core/children/child_inheritance.py
  20. 167
      slither/core/declarations/contract.py
  21. 8
      slither/core/declarations/enum.py
  22. 16
      slither/core/declarations/event.py
  23. 40
      slither/core/declarations/function.py
  24. 16
      slither/core/declarations/solidity_variables.py
  25. 10
      slither/core/declarations/structure.py
  26. 1
      slither/core/solidity_types/__init__.py
  27. 23
      slither/core/solidity_types/type_information.py
  28. 11
      slither/core/source_mapping/source_mapping.py
  29. 5
      slither/core/variables/local_variable.py
  30. 13
      slither/core/variables/state_variable.py
  31. 1
      slither/core/variables/variable.py
  32. 128
      slither/detectors/abstract_detector.py
  33. 13
      slither/detectors/attributes/const_functions.py
  34. 32
      slither/detectors/attributes/incorrect_solc.py
  35. 4
      slither/detectors/erc/incorrect_erc20_interface.py
  36. 6
      slither/detectors/erc/incorrect_erc721_interface.py
  37. 8
      slither/detectors/erc/unindexed_event_parameters.py
  38. 7
      slither/detectors/functions/arbitrary_send.py
  39. 5
      slither/detectors/functions/complex_function.py
  40. 9
      slither/detectors/functions/external_function.py
  41. 7
      slither/detectors/functions/suicidal.py
  42. 70
      slither/detectors/naming_convention/naming_convention.py
  43. 7
      slither/detectors/operations/block_timestamp.py
  44. 6
      slither/detectors/operations/low_level_calls.py
  45. 2
      slither/detectors/operations/unchecked_low_level_return_values.py
  46. 8
      slither/detectors/operations/unused_return_values.py
  47. 2
      slither/detectors/reentrancy/reentrancy.py
  48. 6
      slither/detectors/reentrancy/reentrancy_benign.py
  49. 6
      slither/detectors/reentrancy/reentrancy_eth.py
  50. 6
      slither/detectors/reentrancy/reentrancy_read_before_write.py
  51. 12
      slither/detectors/shadowing/abstract.py
  52. 32
      slither/detectors/shadowing/builtin_symbols.py
  53. 18
      slither/detectors/shadowing/local.py
  54. 14
      slither/detectors/shadowing/state.py
  55. 6
      slither/detectors/statements/assembly.py
  56. 7
      slither/detectors/statements/calls_in_loop.py
  57. 2
      slither/detectors/statements/controlled_delegatecall.py
  58. 10
      slither/detectors/statements/deprecated_calls.py
  59. 6
      slither/detectors/statements/incorrect_strict_equality.py
  60. 8
      slither/detectors/statements/tx_origin.py
  61. 6
      slither/detectors/variables/possible_const_state_variables.py
  62. 7
      slither/detectors/variables/uninitialized_local_variables.py
  63. 5
      slither/detectors/variables/uninitialized_state_variables.py
  64. 4
      slither/detectors/variables/uninitialized_storage_variables.py
  65. 8
      slither/detectors/variables/unused_state_variables.py
  66. 18
      slither/printers/inheritance/inheritance_graph.py
  67. 2
      slither/printers/summary/data_depenency.py
  68. 10
      slither/printers/summary/human_summary.py
  69. 40
      slither/printers/summary/slithir.py
  70. 36
      slither/printers/summary/slithir_ssa.py
  71. 104
      slither/slithir/convert.py
  72. 22
      slither/slithir/operations/internal_call.py
  73. 2
      slither/slithir/utils/ssa.py
  74. 2
      slither/solc_parsing/cfg/node.py
  75. 97
      slither/solc_parsing/declarations/contract.py
  76. 10
      slither/solc_parsing/declarations/function.py
  77. 2
      slither/solc_parsing/exceptions.py
  78. 73
      slither/solc_parsing/expressions/expression_parsing.py
  79. 10
      slither/solc_parsing/slitherSolc.py
  80. 6
      slither/solc_parsing/solidity_types/type_parsing.py
  81. 9
      slither/utils/inheritance_analysis.py
  82. 2
      slither/visitors/slithir/expression_to_slithir.py
  83. 4
      tests/check-upgradeability/test_5.txt
  84. 634
      tests/expected_json/arbitrary_send-0.5.1.arbitrary-send.json
  85. 4
      tests/expected_json/arbitrary_send-0.5.1.arbitrary-send.txt
  86. 634
      tests/expected_json/arbitrary_send.arbitrary-send.json
  87. 4
      tests/expected_json/arbitrary_send.arbitrary-send.txt
  88. 87
      tests/expected_json/backdoor.backdoor.json
  89. 87
      tests/expected_json/backdoor.suicidal.json
  90. 2
      tests/expected_json/backdoor.suicidal.txt
  91. 594
      tests/expected_json/const_state_variables.constable-states.json
  92. 111
      tests/expected_json/constant-0.5.1.constant-function.json
  93. 2
      tests/expected_json/constant-0.5.1.constant-function.txt
  94. 567
      tests/expected_json/constant.constant-function.json
  95. 6
      tests/expected_json/constant.constant-function.txt
  96. 508
      tests/expected_json/controlled_delegatecall.controlled-delegatecall.json
  97. 1164
      tests/expected_json/deprecated_calls.deprecated-standards.json
  98. 378
      tests/expected_json/erc20_indexed.erc20-indexed.json
  99. 408
      tests/expected_json/external_function.external-function.json
  100. 8
      tests/expected_json/external_function.external-function.txt
  101. Some files were not shown because too many files have changed in this diff Show More

@ -18,6 +18,7 @@ env:
- TEST_SUITE=scripts/travis_test_cli.sh
- TEST_SUITE=scripts/travis_test_printers.sh
- TEST_SUITE=scripts/travis_test_slither_config.sh
- TEST_SUITE=scripts/travis_test_simil.sh
branches:
only:
- master

@ -55,7 +55,7 @@ Num | Detector | What it Detects | Impact | Confidence
14 | `constant-function` | [Constant functions changing the state](https://github.com/crytic/slither/wiki/Detector-Documentation#constant-functions-changing-the-state) | Medium | Medium
15 | `reentrancy-no-eth` | [Reentrancy vulnerabilities (no theft of ethers)](https://github.com/crytic/slither/wiki/Detector-Documentation#reentrancy-vulnerabilities-1) | Medium | Medium
16 | `tx-origin` | [Dangerous usage of `tx.origin`](https://github.com/crytic/slither/wiki/Detector-Documentation#dangerous-usage-of-txorigin) | Medium | Medium
17 | `unchecked-lowlevel` | [Unchecked low-level calls](https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-low-level) | Medium | Medium
17 | `unchecked-lowlevel` | [Unchecked low-level calls](https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-low-level-calls) | Medium | Medium
18 | `unchecked-send` | [Unchecked send](https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-send) | Medium | Medium
19 | `uninitialized-local` | [Uninitialized local variables](https://github.com/crytic/slither/wiki/Detector-Documentation#uninitialized-local-variables) | Medium | Medium
20 | `unused-return` | [Unused return values](https://github.com/crytic/slither/wiki/Detector-Documentation#unused-return) | Medium | Medium

@ -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,19 +20,20 @@ generate_expected_json(){
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$output_filename_txt" -i
}
#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"

@ -69,6 +69,7 @@ test_slither(){
}
test_slither tests/solc_version_incorrect_05.ast.json "solc-version"
test_slither tests/unchecked_lowlevel-0.5.1.sol "unchecked-lowlevel"
test_slither tests/unchecked_send-0.5.1.sol "unchecked-send"
test_slither tests/uninitialized-0.5.1.sol "uninitialized-state"
@ -87,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"

@ -10,7 +10,7 @@ chmod +x solc-0.4.25
slither 0x7F37f78cBD74481E593F9C737776F7113d76B315 --solc "./solc-0.4.25"
if [ $? -ne 5 ]
if [ $? -ne 6 ]
then
echo "Etherscan test failed"
exit -1

@ -0,0 +1,21 @@
#!/usr/bin/env bash
### Install requisites
pip3.6 install pybind11
pip3.6 install https://github.com/facebookresearch/fastText/archive/0.2.0.zip
### Test slither-simil
DIR_TESTS="tests/simil"
slither-simil info "" --filename $DIR_TESTS/../complex_func.sol --fname Complex.complexExternalWrites --solc solc-0.4.25 > test_1.txt 2>&1
DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt")
if [ "$DIFF" != "" ]
then
echo "slither-simil failed"
cat test_1.txt
cat "$DIR_TESTS/test_1.txt"
exit -1
fi
rm test_1.txt

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

@ -5,17 +5,18 @@ setup(
description='Slither is a Solidity static analysis framework written in Python 3.',
url='https://github.com/crytic/slither',
author='Trail of Bits',
version='0.6.3',
version='0.6.4',
packages=find_packages(),
python_requires='>=3.6',
install_requires=['prettytable>=0.7.2', 'pysha3>=1.0.2', 'crytic-compile>=0.1.0'],
install_requires=['prettytable>=0.7.2', 'pysha3>=1.0.2', 'crytic-compile>=0.1.1'],
license='AGPL-3.0',
long_description=open('README.md').read(),
entry_points={
'console_scripts': [
'slither = slither.__main__:main',
'slither-check-upgradeability = utils.upgradeability.__main__:main',
'slither-find-paths = utils.possible_paths.__main__:main'
'slither-find-paths = utils.possible_paths.__main__:main',
'slither-simil = utils.similarity.__main__:main'
]
}
)

@ -100,16 +100,26 @@ def process_files(filenames, args, detector_classes, printer_classes):
###################################################################################
def wrap_json_stdout(success, error_message, results=None):
def wrap_json_detectors_results(success, error_message, results=None):
"""
Wrap the detector results.
:param success:
:param error_message:
:param results:
:return:
"""
results_json = {}
if results:
results_json['detectors'] = results
return {
"success": success,
"error": error_message,
"results": results
"results": results_json
}
def output_json(results, filename):
json_result = wrap_json_stdout(True, None, results)
json_result = wrap_json_detectors_results(True, None, results)
if filename is None:
# Write json to console
print(json.dumps(json_result))
@ -594,7 +604,7 @@ def main_impl(all_detector_classes, all_printer_classes):
except SlitherException as se:
# Output our error accordingly, via JSON or logging.
if stdout_json:
print(json.dumps(wrap_json_stdout(False, str(se), [])))
print(json.dumps(wrap_json_detectors_results(False, str(se), [])))
else:
logging.error(red('Error:'))
logging.error(red(se))
@ -604,7 +614,7 @@ def main_impl(all_detector_classes, all_printer_classes):
except Exception:
# Output our error accordingly, via JSON or logging.
if stdout_json:
print(json.dumps(wrap_json_stdout(False, traceback.format_exc(), [])))
print(json.dumps(wrap_json_detectors_results(False, traceback.format_exc(), [])))
else:
logging.error('Error in %s' % args.filename)
logging.error(traceback.format_exc())

@ -2,6 +2,6 @@
This module import all slither exceptions
"""
from slither.slithir.exceptions import SlithIRError
from slither.solc_parsing.exceptions import ParsingError, ParsingContractNotFound, ParsingNameReuse
from slither.solc_parsing.exceptions import ParsingError, ParsingContractNotFound, ParsingNameReuse, VariableNotFound
from slither.core.exceptions import SlitherCoreError
from slither.exceptions import SlitherException

@ -155,6 +155,7 @@ class Node(SourceMapping, ChildFunction):
self._library_calls = []
self._low_level_calls = []
self._external_calls_as_expressions = []
self._internal_calls_as_expressions = []
self._irs = []
self._irs_ssa = []
@ -368,6 +369,13 @@ class Node(SourceMapping, ChildFunction):
"""
return self._external_calls_as_expressions
@property
def internal_calls_as_expressions(self):
"""
list(CallExpression): List of internal calls (that dont create a transaction)
"""
return self._internal_calls_as_expressions
@property
def calls_as_expression(self):
return list(self._expression_calls)

@ -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
###################################################################################
@ -367,45 +449,46 @@ class Contract(ChildSlither, SourceMapping):
'''
return [f for f in self.functions if f.is_writing(variable)]
def get_source_var_declaration(self, var):
""" Return the source mapping where the variable is declared
def get_function_from_signature(self, function_signature):
"""
Return a function from a signature
Args:
var (str): variable name
function_signature (str): signature of the function (without return statement)
Returns:
(dict): sourceMapping
Function
"""
return next((x.source_mapping for x in self.variables if x.name == var))
def get_source_event_declaration(self, event):
""" Return the source mapping where the event is declared
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):
"""
Return a modifier from a signature
Args:
event (str): event name
modifier_name (str): signature of the modifier
Returns:
(dict): sourceMapping
Modifier
"""
return next((x.source_mapping for x in self.events if x.name == event))
return next((m for m in self.modifiers if m.full_name == modifier_signature and not m.is_shadowed), None)
def get_function_from_signature(self, function_signature):
def get_function_from_canonical_name(self, canonical_name):
"""
Return a function from a signature
Return a function from a a canonical name (contract.signature())
Args:
function_signature (str): signature of the function (without return statement)
canonical_name (str): canonical name of the function (without return statement)
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.canonical_name == canonical_name), None)
def get_modifier_from_signature(self, modifier_signature):
def get_modifier_from_canonical_name(self, canonical_name):
"""
Return a modifier from a signature
Return a modifier from a canonical name (contract.signature())
Args:
modifier_name (str): signature of the modifier
canonical_name (str): canonical name of the modifier
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.canonical_name == canonical_name), None)
def get_state_variable_from_name(self, variable_name):
"""
@ -476,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]
@ -490,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
"""
@ -39,8 +40,10 @@ class Function(ChildContract, SourceMapping):
self._slithir_variables = set() # slithir Temporary and references variables (but not SSA)
self._parameters = []
self._parameters_ssa = []
self._parameters_src = None
self._returns = []
self._returns_ssa = []
self._returns_src = None
self._return_values = None
self._return_values_ssa = None
self._vars_read = []
@ -82,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()
@ -114,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):
@ -129,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
###################################################################################
###################################################################################
@ -171,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
###################################################################################
###################################################################################
@ -305,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
@ -558,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]
@ -931,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],

@ -1,6 +1,6 @@
# https://solidity.readthedocs.io/en/v0.4.24/units-and-global-variables.html
from slither.core.context.context import Context
from slither.core.solidity_types import ElementaryType
from slither.core.solidity_types import ElementaryType, TypeInformation
SOLIDITY_VARIABLES = {"now":'uint256',
"this":'address',
@ -57,7 +57,8 @@ SOLIDITY_FUNCTIONS = {"gasleft()":['uint256'],
"abi.encodeWithSelector()":["bytes"],
"abi.encodeWithSignature()":["bytes"],
# abi.decode returns an a list arbitrary types
"abi.decode()":[]}
"abi.decode()":[],
"type(address)":[]}
def solidity_function_signature(name):
"""
@ -125,10 +126,15 @@ class SolidityVariableComposed(SolidityVariable):
class SolidityFunction:
# Non standard handling of type(address). This function returns an undefined object
# The type is dynamic
# https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information
# As a result, we set return_type during the Ir conversion
def __init__(self, name):
assert name in SOLIDITY_FUNCTIONS
self._name = name
self._return_type = [ElementaryType(x) for x in SOLIDITY_FUNCTIONS[self.name]]
@property
def name(self):
@ -140,7 +146,11 @@ class SolidityFunction:
@property
def return_type(self):
return [ElementaryType(x) for x in SOLIDITY_FUNCTIONS[self.name]]
return self._return_type
@return_type.setter
def return_type(self, r):
self._return_type = r
def __str__(self):
return self._name

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

@ -3,3 +3,4 @@ from .elementary_type import ElementaryType
from .function_type import FunctionType
from .mapping_type import MappingType
from .user_defined_type import UserDefinedType
from .type_information import TypeInformation

@ -0,0 +1,23 @@
from slither.core.solidity_types.type import Type
# Use to model the Type(X) function, which returns an undefined type
# https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information
class TypeInformation(Type):
def __init__(self, c):
from slither.core.declarations.contract import Contract
assert isinstance(c, (Contract))
super(TypeInformation, self).__init__()
self._type = c
@property
def type(self):
return self._type
def __str__(self):
return f'type({self.type.name})'
def __eq__(self, other):
if not isinstance(other, TypeInformation):
return False
return self.type == other.type

@ -125,16 +125,7 @@ class SourceMapping(Context):
@property
def source_mapping_str(self):
# def relative_path(path):
# # Remove absolute path for printing
# # Truffle returns absolutePath
# splited_path = path.split(os.sep)
# if 'contracts' in splited_path:
# idx = splited_path.index('contracts')
# return os.sep.join(splited_path[idx-1:])
# return path
lines = self.source_mapping['lines']
lines = self.source_mapping.get('lines', None)
if not lines:
lines = ''
elif len(lines) == 1:

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

@ -146,27 +146,48 @@ class AbstractDetector(metaclass=abc.ABCMeta):
return d
@staticmethod
def _create_base_element(type, name, source_mapping, additional_fields={}):
def _create_base_element(type, name, source_mapping, type_specific_fields={}, additional_fields={}):
element = {'type': type,
'name': name,
'source_mapping': source_mapping}
if type_specific_fields:
element['type_specific_fields'] = type_specific_fields
if additional_fields:
element['additional_fields'] = additional_fields
return element
@staticmethod
def _create_parent_element(element):
from slither.core.children.child_contract import ChildContract
from slither.core.children.child_function import ChildFunction
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)
return contract['elements'][0]
elif isinstance(element, ChildFunction):
if element.function:
function = {'elements': []}
AbstractDetector.add_function_to_json(element.function, function)
return function['elements'][0]
return None
@staticmethod
def add_variable_to_json(variable, d, additional_fields={}):
from slither.core.variables.state_variable import StateVariable
from slither.core.variables.local_variable import LocalVariable
element = AbstractDetector._create_base_element('variable', variable.name, variable.source_mapping, additional_fields)
if isinstance(variable, StateVariable):
contract = {'elements': []}
AbstractDetector.add_contract_to_json(variable.contract, contract)
element['contract'] = contract['elements'][0]
elif isinstance(variable, LocalVariable):
function = {'elements': []}
AbstractDetector.add_function_to_json(variable.function, function)
element['function'] = function['elements'][0]
type_specific_fields = {
'parent': AbstractDetector._create_parent_element(variable)
}
element = AbstractDetector._create_base_element('variable',
variable.name,
variable.source_mapping,
type_specific_fields,
additional_fields)
d['elements'].append(element)
@staticmethod
@ -176,56 +197,84 @@ class AbstractDetector(metaclass=abc.ABCMeta):
@staticmethod
def add_contract_to_json(contract, d, additional_fields={}):
element = AbstractDetector._create_base_element('contract', contract.name, contract.source_mapping, additional_fields)
element = AbstractDetector._create_base_element('contract',
contract.name,
contract.source_mapping,
{},
additional_fields)
d['elements'].append(element)
@staticmethod
def add_function_to_json(function, d, additional_fields={}):
element = AbstractDetector._create_base_element('function', function.name, function.source_mapping, additional_fields)
contract = {'elements':[]}
AbstractDetector.add_contract_to_json(function.contract, contract)
element['contract'] = contract['elements'][0]
type_specific_fields = {
'parent': AbstractDetector._create_parent_element(function),
'signature': function.full_name
}
element = AbstractDetector._create_base_element('function',
function.name,
function.source_mapping,
type_specific_fields,
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={}):
element = AbstractDetector._create_base_element('enum', enum.name, enum.source_mapping, additional_fields)
contract = {'elements': []}
AbstractDetector.add_contract_to_json(enum.contract, contract)
element['contract'] = contract['elements'][0]
type_specific_fields = {
'parent': AbstractDetector._create_parent_element(enum)
}
element = AbstractDetector._create_base_element('enum',
enum.name,
enum.source_mapping,
type_specific_fields,
additional_fields)
d['elements'].append(element)
@staticmethod
def add_struct_to_json(struct, d, additional_fields={}):
element = AbstractDetector._create_base_element('struct', struct.name, struct.source_mapping, additional_fields)
contract = {'elements': []}
AbstractDetector.add_contract_to_json(struct.contract, contract)
element['contract'] = contract['elements'][0]
type_specific_fields = {
'parent': AbstractDetector._create_parent_element(struct)
}
element = AbstractDetector._create_base_element('struct',
struct.name,
struct.source_mapping,
type_specific_fields,
additional_fields)
d['elements'].append(element)
@staticmethod
def add_event_to_json(event, d, additional_fields={}):
element = AbstractDetector._create_base_element('event', event.name, event.source_mapping, additional_fields)
contract = {'elements':[]}
AbstractDetector.add_contract_to_json(event.contract, contract)
element['contract'] = contract['elements'][0]
type_specific_fields = {
'parent': AbstractDetector._create_parent_element(event),
'signature': event.full_name
}
element = AbstractDetector._create_base_element('event',
event.name,
event.source_mapping,
type_specific_fields,
additional_fields)
d['elements'].append(element)
@staticmethod
def add_node_to_json(node, d, additional_fields={}):
type_specific_fields = {
'parent': AbstractDetector._create_parent_element(node),
}
node_name = str(node.expression) if node.expression else ""
element = AbstractDetector._create_base_element('node', node_name, node.source_mapping, additional_fields)
if node.function:
function = {'elements': []}
AbstractDetector.add_function_to_json(node.function, function)
element['function'] = function['elements'][0]
element = AbstractDetector._create_base_element('node',
node_name,
node.source_mapping,
type_specific_fields,
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):
@ -233,10 +282,13 @@ class AbstractDetector(metaclass=abc.ABCMeta):
@staticmethod
def add_pragma_to_json(pragma, d, additional_fields={}):
type_specific_fields = {
'directive': pragma.directive
}
element = AbstractDetector._create_base_element('pragma',
pragma.version,
pragma.source_mapping,
type_specific_fields,
additional_fields)
element['directive'] = pragma.directive
d['elements'].append(element)

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

@ -23,31 +23,43 @@ class IncorrectSolc(AbstractDetector):
IMPACT = DetectorClassification.INFORMATIONAL
CONFIDENCE = DetectorClassification.HIGH
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-version-of-solidity'
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-versions-of-solidity'
WIKI_TITLE = 'Incorrect versions of Solidity'
WIKI_DESCRIPTION = '''
Solc frequently releases new compiler versions. Using an old version prevents access to new Solidity security checks.
We recommend avoiding complex pragma statement.'''
WIKI_RECOMMENDATION = 'Use Solidity 0.4.25 or 0.5.2.'
WIKI_RECOMMENDATION = '''
Use Solidity 0.4.25 or 0.5.3. Consider using the latest version of Solidity for testing the compilation, and a trusted version for deploying.'''
COMPLEX_PRAGMA = "is too complex"
OLD_VERSION = "allows old versions"
LESS_THAN = "uses lesser than"
COMPLEX_PRAGMA_TXT = "is too complex"
OLD_VERSION_TXT = "allows old versions"
LESS_THAN_TXT = "uses lesser than"
TOO_RECENT_VERSION_TXT = "necessitates versions too recent to be trusted. Consider deploying with 0.5.3"
BUGGY_VERSION_TXT = "is known to contain severe issue (https://solidity.readthedocs.io/en/v0.5.8/bugs.html)"
# Indicates the allowed versions.
ALLOWED_VERSIONS = ["0.4.24", "0.4.25", "0.5.2", "0.5.3"]
ALLOWED_VERSIONS = ["0.4.25", "0.4.26", "0.5.3"]
# Indicates the versions too recent.
TOO_RECENT_VERSIONS = ["0.5.4", "0.5.7", "0.5.8", "0.5.9", "0.5.10"]
# Indicates the versions that should not be used.
BUGGY_VERSIONS = ["0.4.22", "0.5.5", "0.5.6", "^0.4.22", "^0.5.5", "^0.5.6"]
def _check_version(self, version):
op = version[0]
if op and not op in ['>', '>=', '^']:
return self.LESS_THAN
return self.LESS_THAN_TXT
version_number = '.'.join(version[2:])
if version_number not in self.ALLOWED_VERSIONS:
return self.OLD_VERSION
if version_number in self.TOO_RECENT_VERSIONS:
return self.TOO_RECENT_VERSION_TXT
return self.OLD_VERSION_TXT
return None
def _check_pragma(self, version):
if version in self.BUGGY_VERSIONS:
return self.BUGGY_VERSION_TXT
versions = PATTERN.findall(version)
if len(versions) == 1:
version = versions[0]
@ -58,10 +70,10 @@ We recommend avoiding complex pragma statement.'''
# Only allow two elements if the second one is
# <0.5.0 or <0.6.0
if version_right not in [('<', '', '0', '5', '0'), ('<', '', '0', '6', '0')]:
return self.COMPLEX_PRAGMA
return self.COMPLEX_PRAGMA_TXT
return self._check_version(version_left)
else:
return self.COMPLEX_PRAGMA
return self.COMPLEX_PRAGMA_TXT
def _detect(self):
"""
Detects pragma statements that allow for outdated solc versions.

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

@ -15,7 +15,7 @@ class UncheckedLowLevel(UnusedReturnValues):
IMPACT = DetectorClassification.MEDIUM
CONFIDENCE = DetectorClassification.MEDIUM
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-low-level'
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-low-level-calls'
WIKI_TITLE = 'Unchecked low-level calls'
WIKI_DESCRIPTION = 'The return value of a low-level call is not checked.'

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

@ -72,13 +72,23 @@ class PrinterHumanSummary(AbstractPrinter):
checks_high = self.slither.detectors_high
issues_informational = [c.detect() for c in checks_informational]
issues_informational = [c for c in issues_informational if c]
issues_informational = [item for sublist in issues_informational for item in sublist]
issues_low = [c.detect() for c in checks_low]
issues_low = [c for c in issues_low if c]
issues_low = [item for sublist in issues_low for item in sublist]
issues_medium = (c.detect() for c in checks_medium)
issues_medium = [c for c in issues_medium if c]
issues_medium = [item for sublist in issues_medium for item in sublist]
issues_high = [c.detect() for c in checks_high]
issues_high = [c for c in issues_high if c]
issues_high = [item for sublist in issues_high for item in sublist]
return (len(issues_informational),
len(issues_low),
len(issues_medium),

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

@ -6,7 +6,7 @@ from slither.core.declarations import (Contract, Enum, Event, Function,
from slither.core.expressions import Identifier, Literal
from slither.core.solidity_types import (ArrayType, ElementaryType,
FunctionType, MappingType,
UserDefinedType)
UserDefinedType, TypeInformation)
from slither.core.solidity_types.elementary_type import Int as ElementaryTypeInt
from slither.core.variables.variable import Variable
from slither.core.variables.state_variable import StateVariable
@ -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:
@ -297,6 +312,44 @@ def propagate_type_and_convert_call(result, node):
idx = idx +1
return result
def _convert_type_contract(ir, slither):
assert isinstance(ir.variable_left.type, TypeInformation)
contract = ir.variable_left.type.type
if ir.variable_right == 'creationCode':
if slither.crytic_compile:
bytecode = slither.crytic_compile.bytecode_init(contract.name)
else:
logger.info(
'The codebase uses type(x).creationCode, but crytic-compile was not used. As a result, the bytecode cannot be found')
bytecode = "MISSING_BYTECODE"
assignment = Assignment(ir.lvalue,
Constant(str(bytecode)),
ElementaryType('bytes'))
assignment.lvalue.set_type(ElementaryType('bytes'))
return assignment
if ir.variable_right == 'runtimeCode':
if slither.crytic_compile:
bytecode = slither.crytic_compile.bytecode_runtime(contract.name)
else:
logger.info(
'The codebase uses type(x).runtimeCode, but crytic-compile was not used. As a result, the bytecode cannot be found')
bytecode = "MISSING_BYTECODE"
assignment = Assignment(ir.lvalue,
Constant(str(bytecode)),
ElementaryType('bytes'))
assignment.lvalue.set_type(ElementaryType('bytes'))
return assignment
if ir.variable_right == 'name':
assignment = Assignment(ir.lvalue,
Constant(contract.name),
ElementaryType('string'))
assignment.lvalue.set_type(ElementaryType('string'))
return assignment
raise SlithIRError(f'type({contract.name}).{ir.variable_right} is unknown')
def propagate_types(ir, node):
# propagate the type
using_for = node.function.contract.using_for
@ -361,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:
@ -398,6 +451,8 @@ def propagate_types(ir, node):
ElementaryType('bytes4'))
assignment.lvalue.set_type(ElementaryType('bytes4'))
return assignment
if isinstance(ir.variable_left, TemporaryVariable) and isinstance(ir.variable_left.type, TypeInformation):
return _convert_type_contract(ir, node.function.slither)
left = ir.variable_left
t = None
if isinstance(left, (Variable, SolidityVariable)):
@ -426,6 +481,12 @@ def propagate_types(ir, node):
f = next((f for f in type_t.functions if f.name == ir.variable_right), None)
if f:
ir.lvalue.set_type(f)
else:
# Allow propgation for variable access through contract's nale
# like Base_contract.my_variable
v = next((v for v in type_t.state_variables if v.name == ir.variable_right), None)
if v:
ir.lvalue.set_type(v.type)
elif isinstance(ir, NewArray):
ir.lvalue.set_type(ir.array_type)
elif isinstance(ir, NewContract):
@ -441,6 +502,8 @@ def propagate_types(ir, node):
elif isinstance(ir, Send):
ir.lvalue.set_type(ElementaryType('bool'))
elif isinstance(ir, SolidityCall):
if ir.function.name == 'type(address)':
ir.function.return_type = [TypeInformation(ir.arguments[0])]
return_type = ir.function.return_type
if len(return_type) == 1:
ir.lvalue.set_type(return_type[0])
@ -472,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]:
@ -647,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:
@ -711,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
@ -874,6 +951,9 @@ def convert_constant_types(irs):
if isinstance(func, StateVariable):
types = export_nested_types_from_variable(func)
else:
if func is None:
# TODO: add POP instruction
break
types = [p.type for p in func.parameters]
for idx, arg in enumerate(ir.arguments):
t = types[idx]

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

@ -62,4 +62,6 @@ class NodeSolc(Node):
pp = FindCalls(expression)
self._expression_calls = pp.result()
self._external_calls_as_expressions = [c for c in self.calls_as_expression if not isinstance(c.called, Identifier)]
self._internal_calls_as_expressions = [c for c in self.calls_as_expression if isinstance(c.called, Identifier)]

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

@ -27,6 +27,7 @@ from slither.utils.utils import unroll
from slither.visitors.expression.export_values import ExportValues
from slither.visitors.expression.has_conditional import HasConditional
from slither.solc_parsing.exceptions import ParsingError
from slither.core.source_mapping.source_mapping import SourceMapping
logger = logging.getLogger("FunctionSolc")
@ -35,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
@ -835,6 +837,9 @@ class FunctionSolc(Function):
def _parse_params(self, params):
assert params[self.get_key()] == 'ParameterList'
self.parameters_src = SourceMapping()
self.parameters_src.set_offset(params['src'], self.contract.slither)
if self.is_compact_ast:
params = params['parameters']
else:
@ -860,6 +865,9 @@ class FunctionSolc(Function):
assert returns[self.get_key()] == 'ParameterList'
self.returns_src = SourceMapping()
self.returns_src.set_offset(returns['src'], self.contract.slither)
if self.is_compact_ast:
returns = returns['parameters']
else:

@ -5,3 +5,5 @@ class ParsingError(SlitherException): pass
class ParsingNameReuse(SlitherException): pass
class ParsingContractNotFound(SlitherException): pass
class VariableNotFound(SlitherException): pass

@ -35,19 +35,11 @@ from slither.core.solidity_types import (ArrayType, ElementaryType,
FunctionType, MappingType)
from slither.solc_parsing.solidity_types.type_parsing import (UnknownType,
parse_type)
from slither.solc_parsing.exceptions import ParsingError
from slither.solc_parsing.exceptions import ParsingError, VariableNotFound
logger = logging.getLogger("ExpressionParsing")
###################################################################################
###################################################################################
# region Exception
###################################################################################
###################################################################################
class VariableNotFound(Exception): pass
# endregion
###################################################################################
###################################################################################
# region Helpers
@ -68,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')
@ -98,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]
@ -157,7 +176,7 @@ def find_variable(var_name, caller_context, referenced_declaration=None):
if function.referenced_declaration == referenced_declaration:
return function
raise VariableNotFound('Variable not found: {}'.format(var_name))
raise VariableNotFound('Variable not found: {} (context {})'.format(var_name, caller_context))
# endregion
###################################################################################
@ -294,7 +313,9 @@ def parse_call(expression, caller_context):
if isinstance(called, SuperCallExpression):
return SuperCallExpression(called, arguments, type_return)
return CallExpression(called, arguments, type_return)
call_expression = CallExpression(called, arguments, type_return)
call_expression.set_offset(expression['src'], caller_context.slither)
return call_expression
def parse_super_name(expression, is_compact_ast):
if is_compact_ast:
@ -536,9 +557,11 @@ 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)
identifier.set_offset(expression['src'], caller_context.slither)
return identifier
elif name == 'IndexAccess':
@ -576,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)
@ -667,6 +679,7 @@ def parse_expression(expression, caller_context):
arguments = [parse_expression(a, caller_context) for a in children[1::]]
call = CallExpression(called, arguments, 'Modifier')
call.set_offset(expression['src'], caller_context.slither)
return call
raise ParsingError('Expression not parsed %s'%name)

@ -136,7 +136,7 @@ class SlitherSolc(Slither):
# match any char for filename
# filename can contain space, /, -, ..
name = re.findall('=* (.+) =*', filename)
name = re.findall('=+ (.+) =+', filename)
if name:
assert len(name) == 1
name = name[0]
@ -148,6 +148,14 @@ class SlitherSolc(Slither):
sourceUnit = re.findall('[0-9]*:[0-9]*:([0-9]*)', data['src'])
if len(sourceUnit) == 1:
sourceUnit = int(sourceUnit[0])
if sourceUnit == -1:
# if source unit is not found
# We can still deduce it, by assigning to the last source_code added
# This works only for crytic compile.
# which used --combined-json ast, rather than --ast-json
# As a result -1 is not used as index
if self.crytic_compile is not None:
sourceUnit = len(self.source_code)
self._source_units[sourceUnit] = name
if os.path.isfile(name) and not name in self.source_code:

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

@ -1,106 +1,15 @@
{
"success": true,
"error": null,
"results": [
{
"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",
"elements": [
{
"type": "function",
"name": "direct",
"source_mapping": {
"start": 162,
"length": 79,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
11,
12,
13
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 884,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "node",
"name": "msg.sender.send(address(this).balance)",
"source_mapping": {
"start": 196,
"length": 38,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
12
],
"starting_column": 9,
"ending_column": 47
},
"function": {
"results": {
"detectors": [
{
"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",
"elements": [
{
"type": "function",
"name": "direct",
"source_mapping": {
@ -118,166 +27,174 @@
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 884,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
}
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 884,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "direct()"
}
}
}
]
},
{
"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",
"elements": [
{
"type": "function",
"name": "indirect",
"source_mapping": {
"start": 316,
"length": 82,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
19,
20,
21
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "Test",
{
"type": "node",
"name": "msg.sender.send(address(this).balance)",
"source_mapping": {
"start": 0,
"length": 884,
"start": 196,
"length": 38,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
12
],
"starting_column": 1,
"ending_column": 2
"starting_column": 9,
"ending_column": 47
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "direct",
"source_mapping": {
"start": 162,
"length": 79,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
11,
12,
13
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 884,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "direct()"
}
}
}
}
},
{
"type": "node",
"name": "destination.send(address(this).balance)",
"source_mapping": {
"start": 352,
"length": 39,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
20
],
"starting_column": 9,
"ending_column": 48
},
"function": {
]
},
{
"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",
"elements": [
{
"type": "function",
"name": "indirect",
"source_mapping": {
@ -295,66 +212,167 @@
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 884,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 884,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "indirect()"
}
},
{
"type": "node",
"name": "destination.send(address(this).balance)",
"source_mapping": {
"start": 352,
"length": 39,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
20
],
"starting_column": 9,
"ending_column": 48
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "indirect",
"source_mapping": {
"start": 316,
"length": 82,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
19,
20,
21
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 884,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_relative": "tests/arbitrary_send-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send-0.5.1.sol",
"filename_short": "tests/arbitrary_send-0.5.1.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "indirect()"
}
}
}
}
}
]
}
]
]
}
]
}
}

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

@ -1,106 +1,15 @@
{
"success": true,
"error": null,
"results": [
{
"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",
"elements": [
{
"type": "function",
"name": "direct",
"source_mapping": {
"start": 147,
"length": 79,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
11,
12,
13
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 869,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
}
}
},
{
"type": "node",
"name": "msg.sender.send(address(this).balance)",
"source_mapping": {
"start": 181,
"length": 38,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
12
],
"starting_column": 9,
"ending_column": 47
},
"function": {
"results": {
"detectors": [
{
"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",
"elements": [
{
"type": "function",
"name": "direct",
"source_mapping": {
@ -118,166 +27,174 @@
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 869,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
}
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 869,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "direct()"
}
}
}
]
},
{
"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",
"elements": [
{
"type": "function",
"name": "indirect",
"source_mapping": {
"start": 301,
"length": 82,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
19,
20,
21
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "Test",
{
"type": "node",
"name": "msg.sender.send(address(this).balance)",
"source_mapping": {
"start": 0,
"length": 869,
"start": 181,
"length": 38,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
12
],
"starting_column": 1,
"ending_column": 2
"starting_column": 9,
"ending_column": 47
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "direct",
"source_mapping": {
"start": 147,
"length": 79,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
11,
12,
13
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 869,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "direct()"
}
}
}
}
},
{
"type": "node",
"name": "destination.send(address(this).balance)",
"source_mapping": {
"start": 337,
"length": 39,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
20
],
"starting_column": 9,
"ending_column": 48
},
"function": {
]
},
{
"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",
"elements": [
{
"type": "function",
"name": "indirect",
"source_mapping": {
@ -295,66 +212,167 @@
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 869,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 869,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "indirect()"
}
},
{
"type": "node",
"name": "destination.send(address(this).balance)",
"source_mapping": {
"start": 337,
"length": 39,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
20
],
"starting_column": 9,
"ending_column": 48
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "indirect",
"source_mapping": {
"start": 301,
"length": 82,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
19,
20,
21
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 869,
"filename_used": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_relative": "tests/arbitrary_send.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/arbitrary_send.sol",
"filename_short": "tests/arbitrary_send.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "indirect()"
}
}
}
}
}
]
}
]
]
}
]
}
}

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

@ -1,56 +1,61 @@
{
"success": true,
"error": null,
"results": [
{
"check": "backdoor",
"impact": "High",
"confidence": "High",
"description": "Backdoor function found in C.i_am_a_backdoor (tests/backdoor.sol#4-6)\n",
"elements": [
{
"type": "function",
"name": "i_am_a_backdoor",
"source_mapping": {
"start": 18,
"length": 74,
"filename_used": "/home/travis/build/crytic/slither/tests/backdoor.sol",
"filename_relative": "tests/backdoor.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/backdoor.sol",
"filename_short": "tests/backdoor.sol",
"lines": [
4,
5,
6
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "C",
"results": {
"detectors": [
{
"check": "backdoor",
"impact": "High",
"confidence": "High",
"description": "Backdoor function found in C.i_am_a_backdoor (tests/backdoor.sol#4-6)\n",
"elements": [
{
"type": "function",
"name": "i_am_a_backdoor",
"source_mapping": {
"start": 1,
"length": 94,
"start": 18,
"length": 74,
"filename_used": "/home/travis/build/crytic/slither/tests/backdoor.sol",
"filename_relative": "tests/backdoor.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/backdoor.sol",
"filename_short": "tests/backdoor.sol",
"lines": [
2,
3,
4,
5,
6,
7,
8
6
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "C",
"source_mapping": {
"start": 1,
"length": 94,
"filename_used": "/home/travis/build/crytic/slither/tests/backdoor.sol",
"filename_relative": "tests/backdoor.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/backdoor.sol",
"filename_short": "tests/backdoor.sol",
"lines": [
2,
3,
4,
5,
6,
7,
8
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "i_am_a_backdoor()"
}
}
}
]
}
]
]
}
]
}
}

@ -1,56 +1,61 @@
{
"success": true,
"error": null,
"results": [
{
"check": "suicidal",
"impact": "High",
"confidence": "High",
"description": "C.i_am_a_backdoor (tests/backdoor.sol#4-6) allows anyone to destruct the contract\n",
"elements": [
{
"type": "function",
"name": "i_am_a_backdoor",
"source_mapping": {
"start": 18,
"length": 74,
"filename_used": "/home/travis/build/crytic/slither/tests/backdoor.sol",
"filename_relative": "tests/backdoor.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/backdoor.sol",
"filename_short": "tests/backdoor.sol",
"lines": [
4,
5,
6
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "C",
"results": {
"detectors": [
{
"check": "suicidal",
"impact": "High",
"confidence": "High",
"description": "C.i_am_a_backdoor() (tests/backdoor.sol#4-6) allows anyone to destruct the contract\n",
"elements": [
{
"type": "function",
"name": "i_am_a_backdoor",
"source_mapping": {
"start": 1,
"length": 94,
"start": 18,
"length": 74,
"filename_used": "/home/travis/build/crytic/slither/tests/backdoor.sol",
"filename_relative": "tests/backdoor.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/backdoor.sol",
"filename_short": "tests/backdoor.sol",
"lines": [
2,
3,
4,
5,
6,
7,
8
6
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "C",
"source_mapping": {
"start": 1,
"length": 94,
"filename_used": "/home/travis/build/crytic/slither/tests/backdoor.sol",
"filename_relative": "tests/backdoor.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/backdoor.sol",
"filename_short": "tests/backdoor.sol",
"lines": [
2,
3,
4,
5,
6,
7,
8
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "i_am_a_backdoor()"
}
}
}
]
}
]
]
}
]
}
}

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

@ -1,348 +1,362 @@
{
"success": true,
"error": null,
"results": [
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "A.myFriendsAddress should be constant (tests/const_state_variables.sol#7)\n",
"elements": [
{
"type": "variable",
"name": "myFriendsAddress",
"source_mapping": {
"start": 132,
"length": 76,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
7
],
"starting_column": 5,
"ending_column": 81
},
"contract": {
"type": "contract",
"name": "A",
"results": {
"detectors": [
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "A.myFriendsAddress should be constant (tests/const_state_variables.sol#7)\n",
"elements": [
{
"type": "variable",
"name": "myFriendsAddress",
"source_mapping": {
"start": 29,
"length": 441,
"start": 132,
"length": 76,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
7
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 81
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "A",
"source_mapping": {
"start": 29,
"length": 441,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
],
"starting_column": 1,
"ending_column": 2
}
}
}
}
}
]
},
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "A.test should be constant (tests/const_state_variables.sol#10)\n",
"elements": [
{
"type": "variable",
"name": "test",
"source_mapping": {
"start": 237,
"length": 20,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
10
],
"starting_column": 5,
"ending_column": 25
},
"contract": {
"type": "contract",
"name": "A",
]
},
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "A.test should be constant (tests/const_state_variables.sol#10)\n",
"elements": [
{
"type": "variable",
"name": "test",
"source_mapping": {
"start": 29,
"length": 441,
"start": 237,
"length": 20,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
10
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 25
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "A",
"source_mapping": {
"start": 29,
"length": 441,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
],
"starting_column": 1,
"ending_column": 2
}
}
}
}
}
]
},
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "A.text2 should be constant (tests/const_state_variables.sol#14)\n",
"elements": [
{
"type": "variable",
"name": "text2",
"source_mapping": {
"start": 333,
"length": 20,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
14
],
"starting_column": 5,
"ending_column": 25
},
"contract": {
"type": "contract",
"name": "A",
]
},
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "A.text2 should be constant (tests/const_state_variables.sol#14)\n",
"elements": [
{
"type": "variable",
"name": "text2",
"source_mapping": {
"start": 29,
"length": 441,
"start": 333,
"length": 20,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
14
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 25
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "A",
"source_mapping": {
"start": 29,
"length": 441,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
],
"starting_column": 1,
"ending_column": 2
}
}
}
}
}
]
},
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "B.mySistersAddress should be constant (tests/const_state_variables.sol#26)\n",
"elements": [
{
"type": "variable",
"name": "mySistersAddress",
"source_mapping": {
"start": 496,
"length": 76,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
26
],
"starting_column": 5,
"ending_column": 81
},
"contract": {
"type": "contract",
"name": "B",
]
},
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "B.mySistersAddress should be constant (tests/const_state_variables.sol#26)\n",
"elements": [
{
"type": "variable",
"name": "mySistersAddress",
"source_mapping": {
"start": 473,
"length": 271,
"start": 496,
"length": 76,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37
26
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 81
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "B",
"source_mapping": {
"start": 473,
"length": 271,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37
],
"starting_column": 1,
"ending_column": 2
}
}
}
}
}
]
},
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "MyConc.should_be_constant should be constant (tests/const_state_variables.sol#42)\n",
"elements": [
{
"type": "variable",
"name": "should_be_constant",
"source_mapping": {
"start": 793,
"length": 42,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
42
],
"starting_column": 5,
"ending_column": 47
},
"contract": {
"type": "contract",
"name": "MyConc",
]
},
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "MyConc.should_be_constant should be constant (tests/const_state_variables.sol#42)\n",
"elements": [
{
"type": "variable",
"name": "should_be_constant",
"source_mapping": {
"start": 746,
"length": 342,
"start": 793,
"length": 42,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52
42
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 47
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "MyConc",
"source_mapping": {
"start": 746,
"length": 342,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52
],
"starting_column": 1,
"ending_column": 2
}
}
}
}
}
]
},
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "MyConc.should_be_constant_2 should be constant (tests/const_state_variables.sol#43)\n",
"elements": [
{
"type": "variable",
"name": "should_be_constant_2",
"source_mapping": {
"start": 841,
"length": 33,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
43
],
"starting_column": 5,
"ending_column": 38
},
"contract": {
"type": "contract",
"name": "MyConc",
]
},
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "MyConc.should_be_constant_2 should be constant (tests/const_state_variables.sol#43)\n",
"elements": [
{
"type": "variable",
"name": "should_be_constant_2",
"source_mapping": {
"start": 746,
"length": 342,
"start": 841,
"length": 33,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52
43
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 38
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "MyConc",
"source_mapping": {
"start": 746,
"length": 342,
"filename_used": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_relative": "tests/const_state_variables.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/const_state_variables.sol",
"filename_short": "tests/const_state_variables.sol",
"lines": [
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52
],
"starting_column": 1,
"ending_column": 2
}
}
}
}
}
]
}
]
]
}
]
}
}

@ -1,70 +1,75 @@
{
"success": true,
"error": null,
"results": [
{
"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",
"elements": [
{
"type": "function",
"name": "test_assembly_bug",
"source_mapping": {
"start": 185,
"length": 66,
"filename_used": "/home/travis/build/crytic/slither/tests/constant-0.5.1.sol",
"filename_relative": "tests/constant-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant-0.5.1.sol",
"filename_short": "tests/constant-0.5.1.sol",
"lines": [
15,
16,
17
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "Constant",
"results": {
"detectors": [
{
"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",
"elements": [
{
"type": "function",
"name": "test_assembly_bug",
"source_mapping": {
"start": 0,
"length": 253,
"start": 185,
"length": 66,
"filename_used": "/home/travis/build/crytic/slither/tests/constant-0.5.1.sol",
"filename_relative": "tests/constant-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant-0.5.1.sol",
"filename_short": "tests/constant-0.5.1.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18
17
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Constant",
"source_mapping": {
"start": 0,
"length": 253,
"filename_used": "/home/travis/build/crytic/slither/tests/constant-0.5.1.sol",
"filename_relative": "tests/constant-0.5.1.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant-0.5.1.sol",
"filename_short": "tests/constant-0.5.1.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "test_assembly_bug()"
}
}
],
"additional_fields": {
"contains_assembly": true
}
],
"additional_fields": {
"contains_assembly": true
}
}
]
]
}
}

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

@ -1,335 +1,350 @@
{
"success": true,
"error": null,
"results": [
{
"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",
"elements": [
{
"type": "function",
"name": "test_view_bug",
"source_mapping": {
"start": 45,
"length": 58,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
5,
6,
7
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "Constant",
"results": {
"detectors": [
{
"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",
"elements": [
{
"type": "function",
"name": "test_view_bug",
"source_mapping": {
"start": 0,
"length": 392,
"start": 45,
"length": 58,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
7
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Constant",
"source_mapping": {
"start": 0,
"length": 392,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "test_view_bug()"
}
}
},
{
"type": "variable",
"name": "a",
"source_mapping": {
"start": 28,
"length": 6,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
3
],
"starting_column": 5,
"ending_column": 11
},
"contract": {
"type": "contract",
"name": "Constant",
{
"type": "variable",
"name": "a",
"source_mapping": {
"start": 0,
"length": 392,
"start": 28,
"length": 6,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
3
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 11
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Constant",
"source_mapping": {
"start": 0,
"length": 392,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
}
}
}
],
"additional_fields": {
"contains_assembly": false
}
],
"additional_fields": {
"contains_assembly": false
}
},
{
"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",
"elements": [
{
"type": "function",
"name": "test_constant_bug",
"source_mapping": {
"start": 113,
"length": 66,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
9,
10,
11
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "Constant",
},
{
"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",
"elements": [
{
"type": "function",
"name": "test_constant_bug",
"source_mapping": {
"start": 0,
"length": 392,
"start": 113,
"length": 66,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
11
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Constant",
"source_mapping": {
"start": 0,
"length": 392,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "test_constant_bug()"
}
}
},
{
"type": "variable",
"name": "a",
"source_mapping": {
"start": 28,
"length": 6,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
3
],
"starting_column": 5,
"ending_column": 11
},
"contract": {
"type": "contract",
"name": "Constant",
{
"type": "variable",
"name": "a",
"source_mapping": {
"start": 0,
"length": 392,
"start": 28,
"length": 6,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
3
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 11
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Constant",
"source_mapping": {
"start": 0,
"length": 392,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
}
}
}
],
"additional_fields": {
"contains_assembly": false
}
],
"additional_fields": {
"contains_assembly": false
}
},
{
"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",
"elements": [
{
"type": "function",
"name": "test_assembly_bug",
"source_mapping": {
"start": 324,
"length": 66,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
22,
23,
24
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "Constant",
},
{
"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",
"elements": [
{
"type": "function",
"name": "test_assembly_bug",
"source_mapping": {
"start": 0,
"length": 392,
"start": 324,
"length": 66,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
24
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Constant",
"source_mapping": {
"start": 0,
"length": 392,
"filename_used": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_relative": "tests/constant.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/constant.sol",
"filename_short": "tests/constant.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "test_assembly_bug()"
}
}
],
"additional_fields": {
"contains_assembly": true
}
],
"additional_fields": {
"contains_assembly": true
}
}
]
]
}
}

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

@ -1,30 +1,98 @@
{
"success": true,
"error": null,
"results": [
{
"check": "controlled-delegatecall",
"impact": "High",
"confidence": "Medium",
"description": "C.bad_delegate_call (tests/controlled_delegatecall.sol#8-11) uses delegatecall to a input-controlled function id\n\t- addr_bad.delegatecall(data) (tests/controlled_delegatecall.sol#10)\n",
"elements": [
{
"type": "node",
"name": "addr_bad.delegatecall(data)",
"source_mapping": {
"start": 201,
"length": 27,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
10
],
"starting_column": 9,
"ending_column": 36
"results": {
"detectors": [
{
"check": "controlled-delegatecall",
"impact": "High",
"confidence": "Medium",
"description": "C.bad_delegate_call (tests/controlled_delegatecall.sol#8-11) uses delegatecall to a input-controlled function id\n\t- addr_bad.delegatecall(data) (tests/controlled_delegatecall.sol#10)\n",
"elements": [
{
"type": "node",
"name": "addr_bad.delegatecall(data)",
"source_mapping": {
"start": 201,
"length": 27,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
10
],
"starting_column": 9,
"ending_column": 36
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "bad_delegate_call",
"source_mapping": {
"start": 101,
"length": 134,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
8,
9,
10,
11
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "C",
"source_mapping": {
"start": 0,
"length": 585,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "bad_delegate_call(bytes)"
}
}
}
},
"function": {
{
"type": "function",
"name": "bad_delegate_call",
"source_mapping": {
@ -43,135 +111,142 @@
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "C",
"source_mapping": {
"start": 0,
"length": 585,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "C",
"source_mapping": {
"start": 0,
"length": 585,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "bad_delegate_call(bytes)"
}
}
},
{
"type": "function",
"name": "bad_delegate_call",
"source_mapping": {
"start": 101,
"length": 134,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
8,
9,
10,
11
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "C",
]
},
{
"check": "controlled-delegatecall",
"impact": "High",
"confidence": "Medium",
"description": "C.bad_delegate_call2 (tests/controlled_delegatecall.sol#18-20) uses delegatecall to a input-controlled function id\n\t- addr_bad.delegatecall(abi.encode(func_id,data)) (tests/controlled_delegatecall.sol#19)\n",
"elements": [
{
"type": "node",
"name": "addr_bad.delegatecall(abi.encode(func_id,data))",
"source_mapping": {
"start": 0,
"length": 585,
"start": 400,
"length": 48,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
19
],
"starting_column": 1,
"ending_column": 2
"starting_column": 9,
"ending_column": 57
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "bad_delegate_call2",
"source_mapping": {
"start": 337,
"length": 118,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
18,
19,
20
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "C",
"source_mapping": {
"start": 0,
"length": 585,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "bad_delegate_call2(bytes)"
}
}
}
}
}
]
},
{
"check": "controlled-delegatecall",
"impact": "High",
"confidence": "Medium",
"description": "C.bad_delegate_call2 (tests/controlled_delegatecall.sol#18-20) uses delegatecall to a input-controlled function id\n\t- addr_bad.delegatecall(abi.encode(func_id,data)) (tests/controlled_delegatecall.sol#19)\n",
"elements": [
{
"type": "node",
"name": "addr_bad.delegatecall(abi.encode(func_id,data))",
"source_mapping": {
"start": 400,
"length": 48,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
19
],
"starting_column": 9,
"ending_column": 57
},
"function": {
{
"type": "function",
"name": "bad_delegate_call2",
"source_mapping": {
@ -189,110 +264,53 @@
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "C",
"source_mapping": {
"start": 0,
"length": 585,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
}
}
},
{
"type": "function",
"name": "bad_delegate_call2",
"source_mapping": {
"start": 337,
"length": 118,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
18,
19,
20
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "C",
"source_mapping": {
"start": 0,
"length": 585,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "C",
"source_mapping": {
"start": 0,
"length": 585,
"filename_used": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_relative": "tests/controlled_delegatecall.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/controlled_delegatecall.sol",
"filename_short": "tests/controlled_delegatecall.sol",
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "bad_delegate_call2(bytes)"
}
}
}
]
}
]
]
}
]
}
}

@ -1,222 +1,236 @@
{
"success": true,
"error": null,
"results": [
{
"check": "erc20-indexed",
"impact": "Informational",
"confidence": "High",
"description": "ERC20 event IERC20Bad.Transfer (tests/erc20_indexed.sol#19) does not index parameter 'from'\n",
"elements": [
{
"type": "event",
"name": "Transfer",
"source_mapping": {
"start": 1090,
"length": 53,
"filename_used": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_relative": "tests/erc20_indexed.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_short": "tests/erc20_indexed.sol",
"lines": [
19
],
"starting_column": 5,
"ending_column": 58
},
"additional_fields": {
"parameter_name": "from"
},
"contract": {
"type": "contract",
"name": "IERC20Bad",
"results": {
"detectors": [
{
"check": "erc20-indexed",
"impact": "Informational",
"confidence": "High",
"description": "ERC20 event IERC20Bad.Transfer (tests/erc20_indexed.sol#19) does not index parameter 'from'\n",
"elements": [
{
"type": "event",
"name": "Transfer",
"source_mapping": {
"start": 622,
"length": 587,
"start": 1090,
"length": 53,
"filename_used": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_relative": "tests/erc20_indexed.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_short": "tests/erc20_indexed.sol",
"lines": [
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
19
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 58
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "IERC20Bad",
"source_mapping": {
"start": 622,
"length": 587,
"filename_used": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_relative": "tests/erc20_indexed.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_short": "tests/erc20_indexed.sol",
"lines": [
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "Transfer(address,address,uint256)"
},
"additional_fields": {
"parameter_name": "from"
}
}
}
]
},
{
"check": "erc20-indexed",
"impact": "Informational",
"confidence": "High",
"description": "ERC20 event IERC20Bad.Transfer (tests/erc20_indexed.sol#19) does not index parameter 'to'\n",
"elements": [
{
"type": "event",
"name": "Transfer",
"source_mapping": {
"start": 1090,
"length": 53,
"filename_used": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_relative": "tests/erc20_indexed.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_short": "tests/erc20_indexed.sol",
"lines": [
19
],
"starting_column": 5,
"ending_column": 58
},
"additional_fields": {
"parameter_name": "to"
},
"contract": {
"type": "contract",
"name": "IERC20Bad",
]
},
{
"check": "erc20-indexed",
"impact": "Informational",
"confidence": "High",
"description": "ERC20 event IERC20Bad.Transfer (tests/erc20_indexed.sol#19) does not index parameter 'to'\n",
"elements": [
{
"type": "event",
"name": "Transfer",
"source_mapping": {
"start": 622,
"length": 587,
"start": 1090,
"length": 53,
"filename_used": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_relative": "tests/erc20_indexed.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_short": "tests/erc20_indexed.sol",
"lines": [
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
19
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 58
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "IERC20Bad",
"source_mapping": {
"start": 622,
"length": 587,
"filename_used": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_relative": "tests/erc20_indexed.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_short": "tests/erc20_indexed.sol",
"lines": [
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "Transfer(address,address,uint256)"
},
"additional_fields": {
"parameter_name": "to"
}
}
}
]
},
{
"check": "erc20-indexed",
"impact": "Informational",
"confidence": "High",
"description": "ERC20 event IERC20Bad.Approval (tests/erc20_indexed.sol#20) does not index parameter 'owner'\n",
"elements": [
{
"type": "event",
"name": "Approval",
"source_mapping": {
"start": 1148,
"length": 59,
"filename_used": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_relative": "tests/erc20_indexed.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_short": "tests/erc20_indexed.sol",
"lines": [
20
],
"starting_column": 5,
"ending_column": 64
},
"additional_fields": {
"parameter_name": "owner"
},
"contract": {
"type": "contract",
"name": "IERC20Bad",
]
},
{
"check": "erc20-indexed",
"impact": "Informational",
"confidence": "High",
"description": "ERC20 event IERC20Bad.Approval (tests/erc20_indexed.sol#20) does not index parameter 'owner'\n",
"elements": [
{
"type": "event",
"name": "Approval",
"source_mapping": {
"start": 622,
"length": 587,
"start": 1148,
"length": 59,
"filename_used": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_relative": "tests/erc20_indexed.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_short": "tests/erc20_indexed.sol",
"lines": [
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
20
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 64
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "IERC20Bad",
"source_mapping": {
"start": 622,
"length": 587,
"filename_used": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_relative": "tests/erc20_indexed.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_short": "tests/erc20_indexed.sol",
"lines": [
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "Approval(address,address,uint256)"
},
"additional_fields": {
"parameter_name": "owner"
}
}
}
]
},
{
"check": "erc20-indexed",
"impact": "Informational",
"confidence": "High",
"description": "ERC20 event IERC20Bad.Approval (tests/erc20_indexed.sol#20) does not index parameter 'spender'\n",
"elements": [
{
"type": "event",
"name": "Approval",
"source_mapping": {
"start": 1148,
"length": 59,
"filename_used": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_relative": "tests/erc20_indexed.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_short": "tests/erc20_indexed.sol",
"lines": [
20
],
"starting_column": 5,
"ending_column": 64
},
"additional_fields": {
"parameter_name": "spender"
},
"contract": {
"type": "contract",
"name": "IERC20Bad",
]
},
{
"check": "erc20-indexed",
"impact": "Informational",
"confidence": "High",
"description": "ERC20 event IERC20Bad.Approval (tests/erc20_indexed.sol#20) does not index parameter 'spender'\n",
"elements": [
{
"type": "event",
"name": "Approval",
"source_mapping": {
"start": 622,
"length": 587,
"start": 1148,
"length": 59,
"filename_used": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_relative": "tests/erc20_indexed.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_short": "tests/erc20_indexed.sol",
"lines": [
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
20
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 64
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "IERC20Bad",
"source_mapping": {
"start": 622,
"length": 587,
"filename_used": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_relative": "tests/erc20_indexed.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/erc20_indexed.sol",
"filename_short": "tests/erc20_indexed.sol",
"lines": [
12,
13,
14,
15,
16,
17,
18,
19,
20,
21
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "Approval(address,address,uint256)"
},
"additional_fields": {
"parameter_name": "spender"
}
}
}
]
}
]
]
}
]
}
}

@ -1,234 +1,220 @@
{
"success": true,
"error": null,
"results": [
{
"check": "external-function",
"impact": "Informational",
"confidence": "High",
"description": "ContractWithFunctionNotCalled.funcNotCalled3 (tests/external_function.sol#13-15) should be declared external\n",
"elements": [
{
"type": "function",
"name": "funcNotCalled3",
"source_mapping": {
"start": 259,
"length": 41,
"filename_used": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_relative": "tests/external_function.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_short": "tests/external_function.sol",
"lines": [
13,
14,
15
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "ContractWithFunctionNotCalled",
"results": {
"detectors": [
{
"check": "external-function",
"impact": "Informational",
"confidence": "High",
"description": "ContractWithFunctionNotCalled.funcNotCalled3() (tests/external_function.sol#13-15) should be declared external\n",
"elements": [
{
"type": "function",
"name": "funcNotCalled3",
"source_mapping": {
"start": 213,
"length": 258,
"start": 259,
"length": 41,
"filename_used": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_relative": "tests/external_function.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_short": "tests/external_function.sol",
"lines": [
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29
15
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "ContractWithFunctionNotCalled",
"source_mapping": {
"start": 213,
"length": 258,
"filename_used": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_relative": "tests/external_function.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_short": "tests/external_function.sol",
"lines": [
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "funcNotCalled3()"
}
}
}
]
},
{
"check": "external-function",
"impact": "Informational",
"confidence": "High",
"description": "ContractWithFunctionNotCalled.funcNotCalled2 (tests/external_function.sol#17-19) should be declared external\n",
"elements": [
{
"type": "function",
"name": "funcNotCalled2",
"source_mapping": {
"start": 306,
"length": 41,
"filename_used": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_relative": "tests/external_function.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_short": "tests/external_function.sol",
"lines": [
17,
18,
19
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "ContractWithFunctionNotCalled",
]
},
{
"check": "external-function",
"impact": "Informational",
"confidence": "High",
"description": "ContractWithFunctionNotCalled.funcNotCalled2() (tests/external_function.sol#17-19) should be declared external\n",
"elements": [
{
"type": "function",
"name": "funcNotCalled2",
"source_mapping": {
"start": 213,
"length": 258,
"start": 306,
"length": 41,
"filename_used": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_relative": "tests/external_function.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_short": "tests/external_function.sol",
"lines": [
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29
19
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "ContractWithFunctionNotCalled",
"source_mapping": {
"start": 213,
"length": 258,
"filename_used": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_relative": "tests/external_function.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_short": "tests/external_function.sol",
"lines": [
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "funcNotCalled2()"
}
}
}
]
},
{
"check": "external-function",
"impact": "Informational",
"confidence": "High",
"description": "ContractWithFunctionNotCalled.funcNotCalled (tests/external_function.sol#21-23) should be declared external\n",
"elements": [
{
"type": "function",
"name": "funcNotCalled",
"source_mapping": {
"start": 353,
"length": 40,
"filename_used": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_relative": "tests/external_function.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_short": "tests/external_function.sol",
"lines": [
21,
22,
23
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "ContractWithFunctionNotCalled",
]
},
{
"check": "external-function",
"impact": "Informational",
"confidence": "High",
"description": "ContractWithFunctionNotCalled.funcNotCalled() (tests/external_function.sol#21-23) should be declared external\n",
"elements": [
{
"type": "function",
"name": "funcNotCalled",
"source_mapping": {
"start": 213,
"length": 258,
"start": 353,
"length": 40,
"filename_used": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_relative": "tests/external_function.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_short": "tests/external_function.sol",
"lines": [
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29
23
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "ContractWithFunctionNotCalled",
"source_mapping": {
"start": 213,
"length": 258,
"filename_used": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_relative": "tests/external_function.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_short": "tests/external_function.sol",
"lines": [
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "funcNotCalled()"
}
}
}
]
},
{
"check": "external-function",
"impact": "Informational",
"confidence": "High",
"description": "ContractWithFunctionNotCalled2.funcNotCalled (tests/external_function.sol#32-39) should be declared external\n",
"elements": [
{
"type": "function",
"name": "funcNotCalled",
"source_mapping": {
"start": 554,
"length": 325,
"filename_used": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_relative": "tests/external_function.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_short": "tests/external_function.sol",
"lines": [
32,
33,
34,
35,
36,
37,
38,
39
],
"starting_column": 5,
"ending_column": 6
},
"contract": {
"type": "contract",
"name": "ContractWithFunctionNotCalled2",
]
},
{
"check": "external-function",
"impact": "Informational",
"confidence": "High",
"description": "ContractWithFunctionNotCalled2.funcNotCalled() (tests/external_function.sol#32-39) should be declared external\n",
"elements": [
{
"type": "function",
"name": "funcNotCalled",
"source_mapping": {
"start": 473,
"length": 408,
"start": 554,
"length": 325,
"filename_used": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_relative": "tests/external_function.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_short": "tests/external_function.sol",
"lines": [
31,
32,
33,
34,
@ -236,15 +222,43 @@
36,
37,
38,
39,
40
39
],
"starting_column": 1,
"ending_column": 2
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "ContractWithFunctionNotCalled2",
"source_mapping": {
"start": 473,
"length": 408,
"filename_used": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_relative": "tests/external_function.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/external_function.sol",
"filename_short": "tests/external_function.sol",
"lines": [
31,
32,
33,
34,
35,
36,
37,
38,
39,
40
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "funcNotCalled()"
}
}
}
]
}
]
]
}
]
}
}

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

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

Loading…
Cancel
Save