Merge branch 'dev' into dev-fix-c3-linearalization

Conflicts:
	slither/core/declarations/structure.py
	slither/core/variables/state_variable.py
	slither/detectors/abstract_detector.py
	slither/detectors/attributes/const_functions.py
	slither/detectors/erc/incorrect_erc20_interface.py
	slither/detectors/erc/unindexed_event_parameters.py
	slither/detectors/naming_convention/naming_convention.py
	slither/detectors/operations/unused_return_values.py
	slither/detectors/statements/calls_in_loop.py
	slither/detectors/statements/incorrect_strict_equality.py
	slither/detectors/statements/tx_origin.py
	slither/detectors/variables/possible_const_state_variables.py
	slither/detectors/variables/unused_state_variables.py
	slither/slithir/convert.py
pull/213/head
Josselin 6 years ago
commit 9439ed65e2
  1. 1
      .travis.yml
  2. 50
      README.md
  3. 69
      scripts/tests_generate_expected_json_4.sh
  4. 9
      scripts/tests_generate_expected_json_5.sh
  5. 8
      scripts/travis_install.sh
  6. 3
      scripts/travis_test_4.sh
  7. 7
      scripts/travis_test_5.sh
  8. 2
      scripts/travis_test_dapp.sh
  9. 4
      scripts/travis_test_etherscan.sh
  10. 21
      scripts/travis_test_simil.sh
  11. 7
      setup.py
  12. 100
      slither/__main__.py
  13. 7
      slither/all_exceptions.py
  14. 2
      slither/analyses/write/are_variables_written.py
  15. 137
      slither/core/declarations/contract.py
  16. 3
      slither/core/declarations/function.py
  17. 16
      slither/core/declarations/solidity_variables.py
  18. 11
      slither/core/declarations/structure.py
  19. 3
      slither/core/exceptions.py
  20. 8
      slither/core/expressions/assignment_operation.py
  21. 8
      slither/core/expressions/binary_operation.py
  22. 7
      slither/core/expressions/literal.py
  23. 11
      slither/core/expressions/unary_operation.py
  24. 8
      slither/core/slither_core.py
  25. 1
      slither/core/solidity_types/__init__.py
  26. 4
      slither/core/solidity_types/array_type.py
  27. 23
      slither/core/solidity_types/type_information.py
  28. 11
      slither/core/source_mapping/source_mapping.py
  29. 46
      slither/core/variables/state_variable.py
  30. 170
      slither/detectors/abstract_detector.py
  31. 8
      slither/detectors/all_detectors.py
  32. 9
      slither/detectors/attributes/const_functions.py
  33. 8
      slither/detectors/attributes/constant_pragma.py
  34. 45
      slither/detectors/attributes/incorrect_solc.py
  35. 2
      slither/detectors/attributes/locked_ether.py
  36. 0
      slither/detectors/erc/__init__.py
  37. 46
      slither/detectors/erc/incorrect_erc20_interface.py
  38. 97
      slither/detectors/erc/incorrect_erc721_interface.py
  39. 17
      slither/detectors/erc/unindexed_event_parameters.py
  40. 10
      slither/detectors/functions/complex_function.py
  41. 100
      slither/detectors/naming_convention/naming_convention.py
  42. 43
      slither/detectors/operations/unchecked_low_level_return_values.py
  43. 40
      slither/detectors/operations/unchecked_send_return_value.py
  44. 33
      slither/detectors/operations/unused_return_values.py
  45. 46
      slither/detectors/reentrancy/reentrancy_benign.py
  46. 46
      slither/detectors/reentrancy/reentrancy_eth.py
  47. 32
      slither/detectors/reentrancy/reentrancy_read_before_write.py
  48. 2
      slither/detectors/shadowing/local.py
  49. 8
      slither/detectors/statements/calls_in_loop.py
  50. 14
      slither/detectors/statements/controlled_delegatecall.py
  51. 18
      slither/detectors/statements/incorrect_strict_equality.py
  52. 78
      slither/detectors/statements/too_many_digits.py
  53. 13
      slither/detectors/statements/tx_origin.py
  54. 11
      slither/detectors/variables/possible_const_state_variables.py
  55. 14
      slither/detectors/variables/unused_state_variables.py
  56. 3
      slither/exceptions.py
  57. 93
      slither/printers/summary/human_summary.py
  58. 34
      slither/slither.py
  59. 152
      slither/slithir/convert.py
  60. 3
      slither/slithir/exceptions.py
  61. 7
      slither/slithir/operations/binary.py
  62. 2
      slither/slithir/operations/return_operation.py
  63. 9
      slither/slithir/operations/unary.py
  64. 4
      slither/slithir/utils/ssa.py
  65. 48
      slither/slithir/variables/constant.py
  66. 4
      slither/solc_parsing/declarations/contract.py
  67. 10
      slither/solc_parsing/declarations/function.py
  68. 2
      slither/solc_parsing/declarations/structure.py
  69. 9
      slither/solc_parsing/exceptions.py
  70. 45
      slither/solc_parsing/expressions/expression_parsing.py
  71. 36
      slither/solc_parsing/slitherSolc.py
  72. 14
      slither/solc_parsing/solidity_types/type_parsing.py
  73. 11
      slither/solc_parsing/variables/variable_declaration.py
  74. 69
      slither/utils/erc.py
  75. 193
      slither/utils/standard_libraries.py
  76. 34
      slither/utils/type.py
  77. 8
      slither/visitors/expression/constants_folding.py
  78. 11
      slither/visitors/expression/expression.py
  79. 9
      slither/visitors/slithir/expression_to_slithir.py
  80. 566
      tests/expected_json/arbitrary_send-0.5.1.arbitrary-send.json
  81. 4
      tests/expected_json/arbitrary_send-0.5.1.arbitrary-send.txt
  82. 566
      tests/expected_json/arbitrary_send.arbitrary-send.json
  83. 4
      tests/expected_json/arbitrary_send.arbitrary-send.txt
  84. 103
      tests/expected_json/backdoor.backdoor.json
  85. 2
      tests/expected_json/backdoor.backdoor.txt
  86. 103
      tests/expected_json/backdoor.suicidal.json
  87. 4
      tests/expected_json/backdoor.suicidal.txt
  88. 446
      tests/expected_json/const_state_variables.constable-states.json
  89. 2
      tests/expected_json/const_state_variables.constable-states.txt
  90. 130
      tests/expected_json/constant-0.5.1.constant-function.json
  91. 2
      tests/expected_json/constant-0.5.1.constant-function.txt
  92. 574
      tests/expected_json/constant.constant-function.json
  93. 6
      tests/expected_json/constant.constant-function.txt
  94. 473
      tests/expected_json/controlled_delegatecall.controlled-delegatecall.json
  95. 4
      tests/expected_json/controlled_delegatecall.controlled-delegatecall.txt
  96. 841
      tests/expected_json/deprecated_calls.deprecated-standards.json
  97. 390
      tests/expected_json/erc20_indexed.erc20-indexed.json
  98. 11
      tests/expected_json/erc20_indexed.erc20-indexed.txt
  99. 488
      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

@ -48,29 +48,33 @@ Num | Detector | What it Detects | Impact | Confidence
7 | `controlled-delegatecall` | [Controlled delegatecall destination](https://github.com/crytic/slither/wiki/Detector-Documentation#controlled-delegatecall) | High | Medium
8 | `reentrancy-eth` | [Reentrancy vulnerabilities (theft of ethers)](https://github.com/crytic/slither/wiki/Detector-Documentation#reentrancy-vulnerabilities) | High | Medium
9 | `erc20-interface` | [Incorrect ERC20 interfaces](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface) | Medium | High
10 | `incorrect-equality` | [Dangerous strict equalities](https://github.com/crytic/slither/wiki/Detector-Documentation#dangerous-strict-equalities) | Medium | High
11 | `locked-ether` | [Contracts that lock ether](https://github.com/crytic/slither/wiki/Detector-Documentation#contracts-that-lock-ether) | Medium | High
12 | `shadowing-abstract` | [State variables shadowing from abstract contracts](https://github.com/crytic/slither/wiki/Detector-Documentation#state-variable-shadowing-from-abstract-contracts) | Medium | High
13 | `constant-function` | [Constant functions changing the state](https://github.com/crytic/slither/wiki/Detector-Documentation#constant-functions-changing-the-state) | Medium | Medium
14 | `reentrancy-no-eth` | [Reentrancy vulnerabilities (no theft of ethers)](https://github.com/crytic/slither/wiki/Detector-Documentation#reentrancy-vulnerabilities-1) | Medium | Medium
15 | `tx-origin` | [Dangerous usage of `tx.origin`](https://github.com/crytic/slither/wiki/Detector-Documentation#dangerous-usage-of-txorigin) | Medium | Medium
16 | `uninitialized-local` | [Uninitialized local variables](https://github.com/crytic/slither/wiki/Detector-Documentation#uninitialized-local-variables) | Medium | Medium
17 | `unused-return` | [Unused return values](https://github.com/crytic/slither/wiki/Detector-Documentation#unused-return) | Medium | Medium
18 | `shadowing-builtin` | [Built-in symbol shadowing](https://github.com/crytic/slither/wiki/Detector-Documentation#builtin-symbol-shadowing) | Low | High
19 | `shadowing-local` | [Local variables shadowing](https://github.com/crytic/slither/wiki/Detector-Documentation#local-variable-shadowing) | Low | High
20 | `calls-loop` | [Multiple calls in a loop](https://github.com/crytic/slither/wiki/Detector-Documentation/_edit#calls-inside-a-loop) | Low | Medium
21 | `reentrancy-benign` | [Benign reentrancy vulnerabilities](https://github.com/crytic/slither/wiki/Detector-Documentation#reentrancy-vulnerabilities-2) | Low | Medium
22 | `timestamp` | [Dangerous usage of `block.timestamp`](https://github.com/crytic/slither/wiki/Detector-Documentation#block-timestamp) | Low | Medium
23 | `assembly` | [Assembly usage](https://github.com/crytic/slither/wiki/Detector-Documentation#assembly-usage) | Informational | High
24 | `constable-states` | [State variables that could be declared constant](https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-constant) | Informational | High
25 | `deprecated-standards` | [Deprecated Solidity Standards](https://github.com/crytic/slither/wiki/Detector-Documentation#deprecated-standards) | Informational | High
26 | `erc20-indexed` | [Un-indexed ERC20 event parameters](https://github.com/crytic/slither/wiki/Detector-Documentation#unindexed-erc20-event-parameters) | Informational | High
27 | `external-function` | [Public function that could be declared as external](https://github.com/crytic/slither/wiki/Detector-Documentation#public-function-that-could-be-declared-as-external) | Informational | High
28 | `low-level-calls` | [Low level calls](https://github.com/crytic/slither/wiki/Detector-Documentation#low-level-calls) | Informational | High
29 | `naming-convention` | [Conformance to Solidity naming conventions](https://github.com/crytic/slither/wiki/Detector-Documentation#conformance-to-solidity-naming-conventions) | Informational | High
30 | `pragma` | [If different pragma directives are used](https://github.com/crytic/slither/wiki/Detector-Documentation#different-pragma-directives-are-used) | Informational | High
31 | `solc-version` | [Incorrect Solidity version (< 0.4.24 or complex pragma)](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-version-of-solidity) | Informational | High
32 | `unused-state` | [Unused state variables](https://github.com/crytic/slither/wiki/Detector-Documentation#unused-state-variables) | Informational | High
10 | `erc721-interface` | [Incorrect ERC721 interfaces](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc721-interface) | Medium | High
11 | `incorrect-equality` | [Dangerous strict equalities](https://github.com/crytic/slither/wiki/Detector-Documentation#dangerous-strict-equalities) | Medium | High
12 | `locked-ether` | [Contracts that lock ether](https://github.com/crytic/slither/wiki/Detector-Documentation#contracts-that-lock-ether) | Medium | High
13 | `shadowing-abstract` | [State variables shadowing from abstract contracts](https://github.com/crytic/slither/wiki/Detector-Documentation#state-variable-shadowing-from-abstract-contracts) | Medium | High
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-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
21 | `shadowing-builtin` | [Built-in symbol shadowing](https://github.com/crytic/slither/wiki/Detector-Documentation#builtin-symbol-shadowing) | Low | High
22 | `shadowing-local` | [Local variables shadowing](https://github.com/crytic/slither/wiki/Detector-Documentation#local-variable-shadowing) | Low | High
23 | `calls-loop` | [Multiple calls in a loop](https://github.com/crytic/slither/wiki/Detector-Documentation/_edit#calls-inside-a-loop) | Low | Medium
24 | `reentrancy-benign` | [Benign reentrancy vulnerabilities](https://github.com/crytic/slither/wiki/Detector-Documentation#reentrancy-vulnerabilities-2) | Low | Medium
25 | `timestamp` | [Dangerous usage of `block.timestamp`](https://github.com/crytic/slither/wiki/Detector-Documentation#block-timestamp) | Low | Medium
26 | `assembly` | [Assembly usage](https://github.com/crytic/slither/wiki/Detector-Documentation#assembly-usage) | Informational | High
27 | `constable-states` | [State variables that could be declared constant](https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-constant) | Informational | High
28 | `deprecated-standards` | [Deprecated Solidity Standards](https://github.com/crytic/slither/wiki/Detector-Documentation#deprecated-standards) | Informational | High
29 | `erc20-indexed` | [Un-indexed ERC20 event parameters](https://github.com/crytic/slither/wiki/Detector-Documentation#unindexed-erc20-event-parameters) | Informational | High
30 | `external-function` | [Public function that could be declared as external](https://github.com/crytic/slither/wiki/Detector-Documentation#public-function-that-could-be-declared-as-external) | Informational | High
31 | `low-level-calls` | [Low level calls](https://github.com/crytic/slither/wiki/Detector-Documentation#low-level-calls) | Informational | High
32 | `naming-convention` | [Conformance to Solidity naming conventions](https://github.com/crytic/slither/wiki/Detector-Documentation#conformance-to-solidity-naming-conventions) | Informational | High
33 | `pragma` | [If different pragma directives are used](https://github.com/crytic/slither/wiki/Detector-Documentation#different-pragma-directives-are-used) | Informational | High
34 | `solc-version` | [Incorrect Solidity version (< 0.4.24 or complex pragma)](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-version-of-solidity) | Informational | High
35 | `unused-state` | [Unused state variables](https://github.com/crytic/slither/wiki/Detector-Documentation#unused-state-variables) | Informational | High
36 | `too-many-digits` | [Conformance to numeric notation best practices](https://github.com/crytic/slither/wiki/Detector-Documentation#too-many-digits) | Informational | Medium
[Contact us](https://www.trailofbits.com/contact/) to get access to additional detectors.

@ -17,39 +17,42 @@ generate_expected_json(){
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$output_filename" -i
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$output_filename_txt" -i
}
#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/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/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"

@ -17,16 +17,15 @@ generate_expected_json(){
slither "$1" --solc-disable-warnings --detect "$2" --json "$output_filename" --solc solc-0.5.1 > $output_filename_txt 2>&1
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$output_filename" -i
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$output_filename_txt" -i
}
generate_expected_json tests/solc_version_incorrect_05.ast.json "solc-version"
generate_expected_json tests/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/pragma.0.4.24.sol "pragma"
generate_expected_json tests/old_solc.sol.json "solc-version"
generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy-eth"
generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy"
generate_expected_json tests/uninitialized_storage_pointer.sol "uninitialized-storage"
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"
@ -34,3 +33,7 @@ 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"

@ -1,4 +1,12 @@
#!/usr/bin/env bash
# TODO: temporary until the next crytic-compile release
git clone https://github.com/crytic/crytic-compile
cd crytic-compile
git checkout dev
python setup.py install
cd ..
python setup.py install
# Used by travis_test.sh
pip install deepdiff

@ -69,9 +69,11 @@ test_slither(){
}
test_slither tests/unchecked_lowlevel.sol "unchecked-lowlevel"
test_slither tests/deprecated_calls.sol "deprecated-standards"
test_slither tests/erc20_indexed.sol "erc20-indexed"
test_slither tests/incorrect_erc20_interface.sol "erc20-interface"
test_slither tests/incorrect_erc721_interface.sol "erc721-interface"
test_slither tests/uninitialized.sol "uninitialized-state"
test_slither tests/backdoor.sol "backdoor"
test_slither tests/backdoor.sol "suicidal"
@ -92,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,9 @@ 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"
test_slither tests/backdoor.sol "backdoor"
test_slither tests/backdoor.sol "suicidal"
@ -85,12 +88,14 @@ 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"
test_slither tests/timestamp.sol "timestamp"
test_slither tests/incorrect_equality.sol "incorrect-equality"
test_slither tests/too_many_digits.sol "too-many-digits"
### Test scripts

@ -14,7 +14,7 @@ dapp init
slither .
if [ $? -eq 21 ]
if [ $? -eq 23 ]
then
exit 0
fi

@ -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
@ -18,7 +18,7 @@ fi
slither rinkeby:0xFe05820C5A92D9bc906D4A46F662dbeba794d3b7 --solc "./solc-0.4.25"
if [ $? -ne 68 ]
if [ $? -ne 76 ]
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

@ -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'
]
}
)

@ -24,11 +24,11 @@ from slither.utils.command_line import (output_detectors, output_results_to_mark
output_detectors_json, output_printers,
output_to_markdown, output_wiki)
from crytic_compile import is_supported
from slither.exceptions import SlitherException
logging.basicConfig()
logger = logging.getLogger("Slither")
###################################################################################
###################################################################################
# region Process functions
@ -99,12 +99,37 @@ def process_files(filenames, args, detector_classes, printer_classes):
###################################################################################
###################################################################################
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_json
}
def output_json(results, filename):
if os.path.isfile(filename):
logger.info(yellow(f'{filename} exists already, the overwrite is prevented'))
json_result = wrap_json_detectors_results(True, None, results)
if filename is None:
# Write json to console
print(json.dumps(json_result))
else:
with open(filename, 'w', encoding='utf8') as f:
json.dump(results, f, indent=2)
# Write json to file
if os.path.isfile(filename):
logger.info(yellow(f'{filename} exists already, the overwrite is prevented'))
else:
with open(filename, 'w', encoding='utf8') as f:
json.dump(json_result, f, indent=2)
# endregion
###################################################################################
@ -327,7 +352,7 @@ def parse_args(detector_classes, printer_classes):
group_misc.add_argument('--json',
help='Export results as JSON',
help='Export the results as a JSON file ("--json -" to export to stdout)',
action='store',
default=defaults_flag_in_config['json'])
@ -456,6 +481,25 @@ class OutputWiki(argparse.Action):
parser.exit()
# endregion
###################################################################################
###################################################################################
# region CustomFormatter
###################################################################################
###################################################################################
class FormatterCryticCompile(logging.Formatter):
def format(self, record):
#for i, msg in enumerate(record.msg):
if record.msg.startswith('Compilation warnings/errors on '):
txt = record.args[1]
txt = txt.split('\n')
txt = [red(x) if 'Error' in x else x for x in txt]
txt = '\n'.join(txt)
record.args = (record.args[0], txt)
return super().format(record)
# endregion
###################################################################################
###################################################################################
@ -463,6 +507,7 @@ class OutputWiki(argparse.Action):
###################################################################################
###################################################################################
def main():
detectors, printers = get_detectors_and_printers()
@ -479,6 +524,11 @@ def main_impl(all_detector_classes, all_printer_classes):
# Set colorization option
set_colorization_enabled(not args.disable_color)
# If we are outputting json to stdout, we'll want to disable any logging.
stdout_json = args.json == "-"
if stdout_json:
logging.disable(logging.CRITICAL)
printer_classes = choose_printers(args, all_printer_classes)
detector_classes = choose_detectors(args, all_detector_classes)
@ -537,7 +587,7 @@ def main_impl(all_detector_classes, all_printer_classes):
raise Exception("Unrecognised file/dir path: '#{filename}'".format(filename=filename))
if args.json:
output_json(results, args.json)
output_json(results, None if stdout_json else args.json)
if args.checklist:
output_results_to_markdown(results)
# Dont print the number of result for printers
@ -551,9 +601,23 @@ def main_impl(all_detector_classes, all_printer_classes):
return
exit(results)
except SlitherException as se:
# Output our error accordingly, via JSON or logging.
if stdout_json:
print(json.dumps(wrap_json_detectors_results(False, str(se), [])))
else:
logging.error(red('Error:'))
logging.error(red(se))
logging.error('Please report an issue to https://github.com/crytic/slither/issues')
sys.exit(-1)
except Exception:
logging.error('Error in %s' % args.filename)
logging.error(traceback.format_exc())
# Output our error accordingly, via JSON or logging.
if stdout_json:
print(json.dumps(wrap_json_detectors_results(False, traceback.format_exc(), [])))
else:
logging.error('Error in %s' % args.filename)
logging.error(traceback.format_exc())
sys.exit(-1)
@ -562,22 +626,6 @@ if __name__ == '__main__':
main()
# endregion
###################################################################################
###################################################################################
# region CustomFormatter
###################################################################################
###################################################################################
class FormatterCryticCompile(logging.Formatter):
def format(self, record):
#for i, msg in enumerate(record.msg):
if record.msg.startswith('Compilation warnings/errors on '):
txt = record.args[1]
txt = txt.split('\n')
txt = [red(x) if 'Error' in x else x for x in txt]
txt = '\n'.join(txt)
record.args = (record.args[0], txt)
return super().format(record)
# endregion

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

@ -33,6 +33,8 @@ def _visit(node, visited, variables_written, variables_to_write):
variables_written = variables_written + [ir.lvalue]
lvalue = ir.lvalue
while isinstance(lvalue, ReferenceVariable):
if lvalue not in refs:
break
variables_written = variables_written + [refs[lvalue]]
lvalue = refs[lvalue]

@ -5,6 +5,9 @@ import logging
from slither.core.children.child_slither import ChildSlither
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.declarations.function import Function
from slither.utils.erc import ERC20_signatures, \
ERC165_signatures, ERC223_signatures, ERC721_signatures, \
ERC1820_signatures, ERC777_signatures
logger = logging.getLogger("Contract")
@ -36,6 +39,8 @@ class Contract(ChildSlither, SourceMapping):
self._using_for = {}
self._kind = None
self._signatures = None
self._initial_state_variables = [] # ssa
@ -269,6 +274,20 @@ class Contract(ChildSlither, SourceMapping):
###################################################################################
###################################################################################
@property
def functions_signatures(self):
"""
Return the signatures of all the public/eterxnal functions/state variables
:return: list(string) the signatures of all the functions that can be called
"""
if self._signatures == None:
sigs = [v.full_name for v in self.state_variables if v.visibility in ['public',
'external']]
sigs += set([f.full_name for f in self.functions if f.visibility in ['public', 'external']])
self._signatures = list(set(sigs))
return self._signatures
@property
def functions(self):
'''
@ -632,19 +651,127 @@ class Contract(ChildSlither, SourceMapping):
"""
return all((not f.is_implemented) for f in self.functions)
# endregion
###################################################################################
###################################################################################
# region ERC conformance
###################################################################################
###################################################################################
def ercs(self):
"""
Return the ERC implemented
:return: list of string
"""
all = [('ERC20', lambda x: x.is_erc20()),
('ERC165', lambda x: x.is_erc165()),
('ERC1820', lambda x: x.is_erc1820()),
('ERC223', lambda x: x.is_erc223()),
('ERC721', lambda x: x.is_erc721()),
('ERC777', lambda x: x.is_erc777())]
return [erc[0] for erc in all if erc[1](self)]
def is_erc20(self):
"""
Check if the contract is an erc20 token
Note: it does not check for correct return values
Returns:
bool
:return: Returns a true if the contract is an erc20
"""
full_names = self.functions_signatures
return all((s in full_names for s in ERC20_signatures))
def is_erc165(self):
"""
Check if the contract is an erc165 token
Note: it does not check for correct return values
:return: Returns a true if the contract is an erc165
"""
full_names = self.functions_signatures
return all((s in full_names for s in ERC165_signatures))
def is_erc1820(self):
"""
Check if the contract is an erc1820
Note: it does not check for correct return values
:return: Returns a true if the contract is an erc165
"""
full_names = self.functions_signatures
return all((s in full_names for s in ERC1820_signatures))
def is_erc223(self):
"""
Check if the contract is an erc223 token
Note: it does not check for correct return values
:return: Returns a true if the contract is an erc223
"""
full_names = self.functions_signatures
return all((s in full_names for s in ERC223_signatures))
def is_erc721(self):
"""
Check if the contract is an erc721 token
Note: it does not check for correct return values
:return: Returns a true if the contract is an erc721
"""
full_names = self.functions_signatures
return all((s in full_names for s in ERC721_signatures))
def is_erc777(self):
"""
Check if the contract is an erc777
Note: it does not check for correct return values
:return: Returns a true if the contract is an erc165
"""
full_names = [f.full_name for f in self.functions]
return 'transfer(address,uint256)' in full_names and\
'transferFrom(address,address,uint256)' in full_names and\
full_names = self.functions_signatures
return all((s in full_names for s in ERC777_signatures))
def is_possible_erc20(self):
"""
Checks if the provided contract could be attempting to implement ERC20 standards.
:param contract: The contract to check for token compatibility.
:return: Returns a boolean indicating if the provided contract met the token standard.
"""
# We do not check for all the functions, as name(), symbol(), might give too many FPs
full_names = self.functions_signatures
return 'transfer(address,uint256)' in full_names or \
'transferFrom(address,address,uint256)' in full_names or \
'approve(address,uint256)' in full_names
def is_possible_erc721(self):
"""
Checks if the provided contract could be attempting to implement ERC721 standards.
:param contract: The contract to check for token compatibility.
:return: Returns a boolean indicating if the provided contract met the token standard.
"""
# We do not check for all the functions, as name(), symbol(), might give too many FPs
full_names = self.functions_signatures
return ('ownerOf(uint256)' in full_names or
'safeTransferFrom(address,address,uint256,bytes)' in full_names or
'safeTransferFrom(address,address,uint256)' in full_names or
'setApprovalForAll(address,bool)' in full_names or
'getApproved(uint256)' in full_names or
'isApprovedForAll(address,address)' in full_names)
# endregion
###################################################################################
###################################################################################
# region Dependencies
###################################################################################
###################################################################################
def is_from_dependency(self):
if self.slither.crytic_compile is None:
return False
return self.slither.crytic_compile.is_dependency(self.source_mapping['filename_absolute'])
# endregion
###################################################################################
###################################################################################

@ -89,6 +89,7 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
self._reachable_from_nodes = set()
self._reachable_from_functions = set()
###################################################################################
###################################################################################
# region General properties
@ -1098,4 +1099,4 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
def __str__(self):
return self._name
# endregion
# endregion

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

@ -10,6 +10,8 @@ class Structure(ChildContract, SourceMapping):
self._name = None
self._canonical_name = None
self._elems = None
# Name of the elements in the order of declaration
self._elems_ordered = None
@property
def canonical_name(self):
@ -23,6 +25,7 @@ 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
@ -31,5 +34,13 @@ class Structure(ChildContract, SourceMapping):
"""
return self.contract == contract
@property
def elems_ordered(self):
ret = []
for e in self._elems_ordered:
ret.append(self._elems[e])
return ret
def __str__(self):
return self.name

@ -0,0 +1,3 @@
from slither.exceptions import SlitherException
class SlitherCoreError(SlitherException): pass

@ -1,7 +1,7 @@
import logging
from slither.core.expressions.expression_typed import ExpressionTyped
from slither.core.expressions.expression import Expression
from slither.core.exceptions import SlitherCoreError
logger = logging.getLogger("AssignmentOperation")
@ -43,8 +43,7 @@ class AssignmentOperationType:
if operation_type == '%=':
return AssignmentOperationType.ASSIGN_MODULO
logger.error('get_type: Unknown operation type {})'.format(operation_type))
exit(-1)
raise SlitherCoreError('get_type: Unknown operation type {})'.format(operation_type))
@staticmethod
def str(operation_type):
@ -71,8 +70,7 @@ class AssignmentOperationType:
if operation_type == AssignmentOperationType.ASSIGN_MODULO:
return '%='
logger.error('str: Unknown operation type {})'.format(operation_type))
exit(-1)
raise SlitherCoreError('str: Unknown operation type {})'.format(operation_type))
class AssignmentOperation(ExpressionTyped):

@ -1,7 +1,7 @@
import logging
from slither.core.expressions.expression_typed import ExpressionTyped
from slither.core.expressions.expression import Expression
from slither.core.exceptions import SlitherCoreError
logger = logging.getLogger("BinaryOperation")
@ -67,8 +67,7 @@ class BinaryOperationType:
if operation_type == '||':
return BinaryOperationType.OROR
logger.error('get_type: Unknown operation type {})'.format(operation_type))
exit(-1)
raise SlitherCoreError('get_type: Unknown operation type {})'.format(operation_type))
@staticmethod
def str(operation_type):
@ -110,8 +109,7 @@ class BinaryOperationType:
return '&&'
if operation_type == BinaryOperationType.OROR:
return '||'
logger.error('str: Unknown operation type {})'.format(operation_type))
exit(-1)
raise SlitherCoreError('str: Unknown operation type {})'.format(operation_type))
class BinaryOperation(ExpressionTyped):

@ -2,14 +2,19 @@ from slither.core.expressions.expression import Expression
class Literal(Expression):
def __init__(self, value):
def __init__(self, value, type):
super(Literal, self).__init__()
self._value = value
self._type = type
@property
def value(self):
return self._value
@property
def type(self):
return self._type
def __str__(self):
# be sure to handle any character
return str(self._value)

@ -1,7 +1,7 @@
import logging
from slither.core.expressions.expression_typed import ExpressionTyped
from slither.core.expressions.expression import Expression
from slither.core.solidity_types.type import Type
from slither.core.exceptions import SlitherCoreError
logger = logging.getLogger("UnaryOperation")
@ -38,8 +38,7 @@ class UnaryOperationType:
return UnaryOperationType.PLUSPLUS_POST
if operation_type == '--':
return UnaryOperationType.MINUSMINUS_POST
logger.error('get_type: Unknown operation type {}'.format(operation_type))
exit(-1)
raise SlitherCoreError('get_type: Unknown operation type {}'.format(operation_type))
@staticmethod
def str(operation_type):
@ -58,8 +57,7 @@ class UnaryOperationType:
if operation_type in [UnaryOperationType.MINUSMINUS_PRE, UnaryOperationType.MINUSMINUS_POST]:
return '--'
logger.error('str: Unknown operation type {}'.format(operation_type))
exit(-1)
raise SlitherCoreError('str: Unknown operation type {}'.format(operation_type))
@staticmethod
def is_prefix(operation_type):
@ -74,8 +72,7 @@ class UnaryOperationType:
elif operation_type in [UnaryOperationType.PLUSPLUS_POST, UnaryOperationType.MINUSMINUS_POST]:
return False
logger.error('is_prefix: Unknown operation type {}'.format(operation_type))
exit(-1)
raise SlitherCoreError('is_prefix: Unknown operation type {}'.format(operation_type))
class UnaryOperation(ExpressionTyped):

@ -56,6 +56,14 @@ class Slither(Context):
"""str: Filename."""
return self._filename
def _add_source_code(self, path):
"""
:param path:
:return:
"""
with open(path, encoding='utf8', newline='') as f:
self.source_code[path] = f.read()
# endregion
###################################################################################
###################################################################################

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

@ -10,7 +10,7 @@ class ArrayType(Type):
assert isinstance(t, Type)
if length:
if isinstance(length, int):
length = Literal(length)
length = Literal(length, 'uint256')
assert isinstance(length, Expression)
super(ArrayType, self).__init__()
self._type = t
@ -18,7 +18,7 @@ class ArrayType(Type):
if length:
if not isinstance(length, Literal):
cf = ConstantFolding(length)
cf = ConstantFolding(length, "uint256")
length = cf.result()
self._length_value = length
else:

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

@ -1,8 +1,10 @@
from .variable import Variable
from slither.core.children.child_contract import ChildContract
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
@ -11,8 +13,52 @@ class StateVariable(ChildContract, Variable):
"""
return self.contract == contract
###################################################################################
###################################################################################
# region Signature
###################################################################################
###################################################################################
@property
def signature(self):
"""
Return the signature of the state variable as a function signature
:return: (str, list(str), list(str)), as (name, list parameters type, list return values type)
"""
return self.name, [str(x) for x in export_nested_types_from_variable(self)], self.type
@property
def signature_str(self):
"""
Return the signature of the state variable as a function signature
:return: str: func_name(type1,type2) returns(type3)
"""
name, parameters, returnVars = self.signature
return name+'('+','.join(parameters)+') returns('+','.join(returnVars)+')'
# endregion
###################################################################################
###################################################################################
# region Name
###################################################################################
###################################################################################
@property
def canonical_name(self):
return '{}.{}'.format(self.contract.name, self.name)
@property
def full_name(self):
"""
Return the name of the state variable as a function signaure
str: func_name(type1,type2)
:return: the function signature without the return values
"""
name, parameters, _ = self.signature
return name+'('+','.join(parameters)+')'
# endregion
###################################################################################
###################################################################################

@ -86,12 +86,6 @@ class AbstractDetector(metaclass=abc.ABCMeta):
DetectorClassification.INFORMATIONAL]:
raise IncorrectDetectorInitialization('CONFIDENCE is not initialized {}'.format(self.__class__.__name__))
# def log(self, info):
# if self.logger:
# info = "\n"+info
# if self.WIKI != '':
# info += 'Reference: {}'.format(self.WIKI)
# self.logger.info(self.color(info))
def _log(self, info):
self.logger.info(self.color(info))
@ -140,20 +134,61 @@ class AbstractDetector(metaclass=abc.ABCMeta):
def color(self):
return classification_colors[self.IMPACT]
def generate_json_result(self, info):
def generate_json_result(self, info, additional_fields={}):
d = OrderedDict()
d['check'] = self.ARGUMENT
d['impact'] = classification_txt[self.IMPACT]
d['confidence'] = classification_txt[self.CONFIDENCE]
d['description'] = info
d['elements'] = []
if additional_fields:
d['additional_fields'] = additional_fields
return d
@staticmethod
def add_variable_to_json(variable, d):
d['elements'].append({'type': 'variable',
'name': variable.name,
'source_mapping': variable.source_mapping})
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.declarations import Function
if isinstance(element, Function):
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={}):
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
def add_variables_to_json(variables, d):
@ -161,44 +196,99 @@ class AbstractDetector(metaclass=abc.ABCMeta):
AbstractDetector.add_variable_to_json(variable, d)
@staticmethod
def add_contract_to_json(contract, d):
d['elements'].append({'type': 'contract',
'name': contract.name,
'source_mapping': contract.source_mapping})
def add_contract_to_json(contract, d, 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):
contract = {'elements':[]}
AbstractDetector.add_contract_to_json(function.contract_declarer, contract)
d['elements'].append({'type': 'function',
'name': function.name,
'source_mapping': function.source_mapping,
'contract': contract['elements'][0]})
# We use the same json type for function and event to facilitate the third-party tools parsing
@staticmethod
def add_event_to_json(event, d):
contract = {'elements':[]}
AbstractDetector.add_contract_to_json(event.contract, contract)
d['elements'].append({'type': 'function',
'name': event.name,
'source_mapping': event.source_mapping,
'contract': contract['elements'][0]})
def add_function_to_json(function, d, additional_fields={}):
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={}):
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={}):
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_events_to_json(events, d):
for event in sorted(events, key=lambda x: x.name):
AbstractDetector.add_event_to_json(event, d)
def add_event_to_json(event, d, additional_fields={}):
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,
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):
d['elements'].append({'type': 'expression',
'expression': str(node.expression),
'source_mapping': node.source_mapping})
AbstractDetector.add_node_to_json(node, d)
@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)
d['elements'].append(element)

@ -28,9 +28,13 @@ from .shadowing.builtin_symbols import BuiltinSymbolShadowing
from .operations.block_timestamp import Timestamp
from .statements.calls_in_loop import MultipleCallsInLoop
from .statements.incorrect_strict_equality import IncorrectStrictEquality
from .erc20.incorrect_interface import IncorrectERC20InterfaceDetection
from .erc20.unindexed_event_parameters import UnindexedERC20EventParameters
from .erc.incorrect_erc20_interface import IncorrectERC20InterfaceDetection
from .erc.incorrect_erc721_interface import IncorrectERC721InterfaceDetection
from .erc.unindexed_event_parameters import UnindexedERC20EventParameters
from .statements.deprecated_calls import DeprecatedStandards
from .source.rtlo import RightToLeftOverride
from .statements.too_many_digits import TooManyDigits
from .operations.unchecked_low_level_return_values import UncheckedLowLevel
from .operations.unchecked_send_return_value import UncheckedSend
#
#

@ -58,10 +58,8 @@ All the calls to `get` revert, breaking Bob's smart contract execution.'''
attr = 'view' if f.view else 'pure'
info = '{} ({}) is declared {} but contains assembly code\n'
info = info.format(f.canonical_name, f.source_mapping_str, attr)
json = self.generate_json_result(info)
json = self.generate_json_result(info, {'contains_assembly': True})
self.add_function_to_json(f, json)
json['elements'].append({'type': 'info',
'contains_assembly' : True})
results.append(json)
variables_written = f.all_state_variables_written()
@ -72,12 +70,9 @@ All the calls to `get` revert, breaking Bob's smart contract execution.'''
for variable_written in variables_written:
info += '\t- {}\n'.format(variable_written.canonical_name)
json = self.generate_json_result(info)
json = self.generate_json_result(info, {'contains_assembly': False})
self.add_function_to_json(f, json)
self.add_variables_to_json(variables_written, json)
json['elements'].append({'type': 'info',
'contains_assembly' : False})
results.append(json)
return results

@ -35,10 +35,10 @@ class ConstantPragma(AbstractDetector):
info += "\t- {} declares {}\n".format(p.source_mapping_str, str(p))
json = self.generate_json_result(info)
# follow the same format than add_nodes_to_json
json['elements'] = [{'type': 'expression',
'expression': p.version,
'source_mapping': p.source_mapping} for p in pragma]
# Add each pragma to our elements
for p in pragma:
self.add_pragma_to_json(p, json)
results.append(json)
return results

@ -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 has a complex pragma"
OLD_VERSION = "it allows old versions"
LESS_THAN = "it 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.
@ -85,16 +97,11 @@ We recommend avoiding complex pragma statement.'''
# If we found any disallowed pragmas, we output our findings.
if disallowed_pragmas:
info = "Detected issues with version pragma in {}:\n".format(self.filename)
for (reason, p) in disallowed_pragmas:
info += "\t- {} ({}): {}\n".format(p, p.source_mapping_str, reason)
json = self.generate_json_result(info)
info = f"Pragma version \"{p.version}\" {reason} ({p.source_mapping_str})\n"
# follow the same format than add_nodes_to_json
json['elements'] = [{'type': 'expression',
'expression': p.version,
'source_mapping': p.source_mapping} for (reason, p) in disallowed_pragmas]
results.append(json)
json = self.generate_json_result(info)
self.add_pragma_to_json(p, json)
results.append(json)
return results

@ -84,8 +84,8 @@ Every ether sent to `Locked` will be lost.'''
[f.name for f in funcs_payable])
json = self.generate_json_result(info)
self.add_functions_to_json(funcs_payable, json)
self.add_contract_to_json(contract, json)
self.add_functions_to_json(funcs_payable, json)
results.append(json)
return results

@ -18,7 +18,7 @@ class IncorrectERC20InterfaceDetection(AbstractDetector):
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface'
WIKI_TITLE = 'Incorrect erc20 interface'
WIKI_DESCRIPTION = 'Lack of return value for the ERC20 `approve`/`transfer`/`transferFrom` functions. A contract compiled with solidity > 0.4.22 interacting with these functions will fail to execute them, as the return value is missing.'
WIKI_DESCRIPTION = 'Incorrect return values for ERC20 functions. A contract compiled with solidity > 0.4.22 interacting with these functions will fail to execute them, as the return value is missing.'
WIKI_EXPLOIT_SCENARIO = '''
```solidity
contract Token{
@ -28,7 +28,7 @@ contract Token{
```
`Token.transfer` does not return a boolean. Bob deploys the token. Alice creates a contract that interacts with it but assumes a correct ERC20 interface implementation. Alice's contract is unable to interact with Bob's contract.'''
WIKI_RECOMMENDATION = 'Return a boolean for the `approve`/`transfer`/`transferFrom` functions.'
WIKI_RECOMMENDATION = 'Set the appropriate return values and value-types for the defined ERC20 functions.'
@staticmethod
def incorrect_erc20_interface(signature):
@ -43,6 +43,15 @@ contract Token{
if name == 'approve' and parameters == ['address', 'uint256'] and returnVars != ['bool']:
return True
if name == 'allowance' and parameters == ['address', 'address'] and returnVars != ['uint256']:
return True
if name == 'balanceOf' and parameters == ['address'] and returnVars != ['uint256']:
return True
if name == 'totalSupply' and parameters == [] and returnVars != ['uint256']:
return True
return False
@staticmethod
@ -52,27 +61,38 @@ contract Token{
Returns:
list(str) : list of incorrect function signatures
"""
functions = [f for f in contract.functions if f.contract_declarer == contract and \
IncorrectERC20InterfaceDetection.incorrect_erc20_interface(f.signature)]
# Verify this is an ERC20 contract.
if not contract.is_possible_erc20():
return []
# If this contract implements a function from ERC721, we can assume it is an ERC721 token. These tokens
# offer functions which are similar to ERC20, but are not compatible.
if contract.is_possible_erc721():
return []
funcs = contract.functions
functions = [f for f in funcs if IncorrectERC20InterfaceDetection.incorrect_erc20_interface(f.signature)]
return functions
def _detect(self):
""" Detect incorrect erc20 interface
Returns:
dict: [contrat name] = set(str) events
dict: [contract name] = set(str) events
"""
results = []
for c in self.contracts:
for c in self.slither.contracts_derived:
functions = IncorrectERC20InterfaceDetection.detect_incorrect_erc20_interface(c)
if functions:
info = "{} ({}) has incorrect ERC20 function interface(s):\n"
info = info.format(c.name,
c.source_mapping_str)
for function in functions:
info += "\t-{} ({})\n".format(function.name, function.source_mapping_str)
json = self.generate_json_result(info)
self.add_functions_to_json(functions, json)
results.append(json)
info = "{} ({}) has incorrect ERC20 function interface: {} ({})\n".format(c.name,
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)
return results

@ -0,0 +1,97 @@
"""
Detect incorrect erc721 interface.
"""
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
class IncorrectERC721InterfaceDetection(AbstractDetector):
"""
Incorrect ERC721 Interface
"""
ARGUMENT = 'erc721-interface'
HELP = 'Incorrect ERC721 interfaces'
IMPACT = DetectorClassification.MEDIUM
CONFIDENCE = DetectorClassification.HIGH
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc721-interface'
WIKI_TITLE = 'Incorrect erc721 interface'
WIKI_DESCRIPTION = 'Incorrect return values for ERC721 functions. A contract compiled with solidity > 0.4.22 interacting with these functions will fail to execute them, as the return value is missing.'
WIKI_EXPLOIT_SCENARIO = '''
```solidity
contract Token{
function ownerOf(uint256 _tokenId) external view returns (bool);
//...
}
```
`Token.ownerOf` does not return an address as ERC721 expects. Bob deploys the token. Alice creates a contract that interacts with it but assumes a correct ERC721 interface implementation. Alice's contract is unable to interact with Bob's contract.'''
WIKI_RECOMMENDATION = 'Set the appropriate return values and value-types for the defined ERC721 functions.'
@staticmethod
def incorrect_erc721_interface(signature):
(name, parameters, returnVars) = signature
# ERC721
if name == 'balanceOf' and parameters == ['address'] and returnVars != ['uint256']:
return True
if name == 'ownerOf' and parameters == ['uint256'] and returnVars != ['address']:
return True
if name == 'safeTransferFrom' and parameters == ['address', 'address', 'uint256', 'bytes'] and returnVars != []:
return True
if name == 'safeTransferFrom' and parameters == ['address', 'address', 'uint256'] and returnVars != []:
return True
if name == 'transferFrom' and parameters == ['address', 'address', 'uint256'] and returnVars != []:
return True
if name == 'approve' and parameters == ['address', 'uint256'] and returnVars != []:
return True
if name == 'setApprovalForAll' and parameters == ['address', 'bool'] and returnVars != []:
return True
if name == 'getApproved' and parameters == ['uint256'] and returnVars != ['address']:
return True
if name == 'isApprovedForAll' and parameters == ['address', 'address'] and returnVars != ['bool']:
return True
# ERC165 (dependency)
if name == 'supportsInterface' and parameters == ['bytes4'] and returnVars != ['bool']:
return True
return False
@staticmethod
def detect_incorrect_erc721_interface(contract):
""" Detect incorrect ERC721 interface
Returns:
list(str) : list of incorrect function signatures
"""
# Verify this is an ERC721 contract.
if not contract.is_possible_erc721() or not contract.is_possible_erc20():
return []
funcs = contract.functions
functions = [f for f in funcs if IncorrectERC721InterfaceDetection.incorrect_erc721_interface(f.signature)]
return functions
def _detect(self):
""" Detect incorrect erc721 interface
Returns:
dict: [contract name] = set(str) events
"""
results = []
for c in self.slither.contracts_derived:
functions = IncorrectERC721InterfaceDetection.detect_incorrect_erc721_interface(c)
if functions:
for function in functions:
info = "{} ({}) has incorrect ERC721 function interface: {} ({})\n".format(c.name,
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)
return results

@ -68,14 +68,17 @@ In this case, Transfer and Approval events should have the 'indexed' keyword on
for c in self.contracts:
unindexed_params = self.detect_erc20_unindexed_event_params(c)
if unindexed_params:
info = "{} ({}) does not mark important ERC20 parameters as 'indexed':\n"
info = info.format(c.name, c.source_mapping_str)
# Add each problematic event definition to our result list
for (event, parameter) in unindexed_params:
info += "\t-{} ({}) does not index parameter '{}'\n".format(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).
json = self.generate_json_result(info)
self.add_events_to_json([event for event, _ in unindexed_params], json)
results.append(json)
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).
json = self.generate_json_result(info)
self.add_event_to_json(event, json, {
"parameter_name": parameter.name
})
results.append(json)
return results

@ -105,10 +105,12 @@ class ComplexFunction(AbstractDetector):
self.log(info)
json = self.generate_json_result(info)
self.add_function_to_json(func, json)
json['high_number_of_external_calls'] = cause == self.CAUSE_EXTERNAL_CALL
json['high_number_of_branches'] = cause == self.CAUSE_CYCLOMATIC
json['high_number_of_state_variables'] = cause == self.CAUSE_STATE_VARS
self.add_function_to_json(func, json, {
'high_number_of_external_calls': cause == self.CAUSE_EXTERNAL_CALL,
'high_number_of_branches': cause == self.CAUSE_CYCLOMATIC,
'high_number_of_state_variables': cause == self.CAUSE_STATE_VARS
})
results.append(json)
return results

@ -61,12 +61,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
contract.source_mapping_str)
json = self.generate_json_result(info)
elem = dict()
elem['target'] = 'contract'
elem['convention'] = 'CapWords'
elem['name'] = contract.name
elem['source_mapping'] = contract.source_mapping
json['elements'] = [elem]
self.add_contract_to_json(contract, json, {
"target": "contract",
"convention": "CapWords"
})
results.append(json)
for struct in contract.structures_declared:
@ -75,12 +73,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
info = info.format(struct.canonical_name, struct.source_mapping_str)
json = self.generate_json_result(info)
elem = dict()
elem['target'] = 'structure'
elem['convention'] = 'CapWords'
elem['name'] = struct.name
elem['source_mapping'] = struct.source_mapping
json['elements'] = [elem]
self.add_struct_to_json(struct, json, {
"target": "structure",
"convention": "CapWords"
})
results.append(json)
for event in contract.events_declared:
@ -89,12 +85,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
info = info.format(event.canonical_name, event.source_mapping_str)
json = self.generate_json_result(info)
elem = dict()
elem['target'] = 'event'
elem['convention'] = 'CapWords'
elem['name'] = event.name
elem['source_mapping'] = event.source_mapping
json['elements'] = [elem]
self.add_event_to_json(event, json, {
"target": "event",
"convention": "CapWords"
})
results.append(json)
for func in contract.functions_declared:
@ -103,12 +97,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
info = info.format(func.canonical_name, func.source_mapping_str)
json = self.generate_json_result(info)
elem = dict()
elem['target'] = 'function'
elem['convention'] = 'mixedCase'
elem['name'] = func.name
elem['source_mapping'] = func.source_mapping
json['elements'] = [elem]
self.add_function_to_json(func, json, {
"target": "function",
"convention": "mixedCase"
})
results.append(json)
for argument in func.parameters:
@ -123,12 +115,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
argument.source_mapping_str)
json = self.generate_json_result(info)
elem = dict()
elem['target'] = 'parameter'
elem['convention'] = 'mixedCase'
elem['name'] = argument.name
elem['source_mapping'] = argument.source_mapping
json['elements'] = [elem]
self.add_variable_to_json(argument, json, {
"target": "parameter",
"convention": "mixedCase"
})
results.append(json)
for var in contract.state_variables_declared:
@ -138,12 +128,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
info = info.format(var.canonical_name, var.source_mapping_str)
json = self.generate_json_result(info)
elem = dict()
elem['target'] = 'variable'
elem['convention'] = 'l_O_I_should_not_be_used'
elem['name'] = var.name
elem['source_mapping'] = var.source_mapping
json['elements'] = [elem]
self.add_variable_to_json(var, json, {
"target": "variable",
"convention": "l_O_I_should_not_be_used"
})
results.append(json)
if var.is_constant is True:
@ -156,12 +144,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
info = info.format(var.canonical_name, var.source_mapping_str)
json = self.generate_json_result(info)
elem = dict()
elem['target'] = 'variable_constant'
elem['convention'] = 'UPPER_CASE_WITH_UNDERSCORES'
elem['name'] = var.name
elem['source_mapping'] = var.source_mapping
json['elements'] = [elem]
self.add_variable_to_json(var, json, {
"target": "variable_constant",
"convention": "UPPER_CASE_WITH_UNDERSCORES"
})
results.append(json)
else:
@ -174,12 +160,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
info = info.format(var.canonical_name, var.source_mapping_str)
json = self.generate_json_result(info)
elem = dict()
elem['target'] = 'variable'
elem['convention'] = 'mixedCase'
elem['name'] = var.name
elem['source_mapping'] = var.source_mapping
json['elements'] = [elem]
self.add_variable_to_json(var, json, {
"target": "variable",
"convention": "mixedCase"
})
results.append(json)
for enum in contract.enums_declared:
@ -188,12 +172,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
info = info.format(enum.canonical_name, enum.source_mapping_str)
json = self.generate_json_result(info)
elem = dict()
elem['target'] = 'enum'
elem['convention'] = 'CapWords'
elem['name'] = enum.name
elem['source_mapping'] = enum.source_mapping
json['elements'] = [elem]
self.add_enum_to_json(enum, json, {
"target": "enum",
"convention": "CapWords"
})
results.append(json)
for modifier in contract.modifiers_declared:
@ -203,12 +185,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
modifier.source_mapping_str)
json = self.generate_json_result(info)
elem = dict()
elem['target'] = 'modifier'
elem['convention'] = 'mixedCase'
elem['name'] = modifier.name
elem['source_mapping'] = modifier.source_mapping
json['elements'] = [elem]
self.add_function_to_json(modifier, json, {
"target": "modifier",
"convention": "mixedCase"
})
results.append(json)
return results

@ -0,0 +1,43 @@
"""
Module detecting unused return values from low level
"""
from slither.detectors.abstract_detector import DetectorClassification
from .unused_return_values import UnusedReturnValues
from slither.slithir.operations import LowLevelCall
class UncheckedLowLevel(UnusedReturnValues):
"""
If the return value of a send is not checked, it might lead to losing ether
"""
ARGUMENT = 'unchecked-lowlevel'
HELP = 'Unchecked low-level calls'
IMPACT = DetectorClassification.MEDIUM
CONFIDENCE = DetectorClassification.MEDIUM
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.'
WIKI_EXPLOIT_SCENARIO = '''
```solidity
contract MyConc{
function my_func(address payable dst) public payable{
dst.call.value(msg.value)("");
}
}
```
The return value of the low-level call is not checked. As a result if the callfailed, the ether will be locked in the contract.
If the low level is used to prevent blocking operations, consider logging failed calls.
'''
WIKI_RECOMMENDATION = 'Ensure that the return value of low-level call is checked or logged.'
_txt_description = "low-level calls"
def _is_instance(self, ir):
return isinstance(ir, LowLevelCall)

@ -0,0 +1,40 @@
"""
Module detecting unused return values from send
"""
from slither.detectors.abstract_detector import DetectorClassification
from .unused_return_values import UnusedReturnValues
from slither.slithir.operations import Send
class UncheckedSend(UnusedReturnValues):
"""
If the return value of a send is not checked, it might lead to losing ether
"""
ARGUMENT = 'unchecked-send'
HELP = 'Unchecked send'
IMPACT = DetectorClassification.MEDIUM
CONFIDENCE = DetectorClassification.MEDIUM
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-send'
WIKI_TITLE = 'Unchecked Send'
WIKI_DESCRIPTION = 'The return value of a send is not checked.'
WIKI_EXPLOIT_SCENARIO = '''
```solidity
contract MyConc{
function my_func(address payable dst) public payable{
dst.send(msg.value);
}
}
```
The return value of `send` is not checked. As a result if the send failed, the ether will be locked in the contract.
If `send` is used to prevent blocking operations, consider logging the failed sent.
'''
WIKI_RECOMMENDATION = 'Ensure that the return value of send is checked or logged.'
_txt_description = "send calls"
def _is_instance(self, ir):
return isinstance(ir, Send)

@ -2,9 +2,8 @@
Module detecting unused return values from external calls
"""
from collections import defaultdict
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations.high_level_call import HighLevelCall
from slither.slithir.operations import HighLevelCall, InternalCall, InternalDynamicCall
from slither.core.variables.state_variable import StateVariable
class UnusedReturnValues(AbstractDetector):
@ -19,7 +18,6 @@ class UnusedReturnValues(AbstractDetector):
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#unused-return'
WIKI_TITLE = 'Unused return'
WIKI_DESCRIPTION = 'The return value of an external call is not stored in a local or state variable.'
WIKI_EXPLOIT_SCENARIO = '''
@ -33,7 +31,12 @@ contract MyConc{
```
`MyConc` calls `add` of SafeMath, but does not store the result in `a`. As a result, the computation has no effect.'''
WIKI_RECOMMENDATION = 'Ensure that all the return values of the function calls are stored in a local or state variable.'
WIKI_RECOMMENDATION = 'Ensure that all the return values of the function calls are used.'
_txt_description = "external calls"
def _is_instance(self, ir):
return isinstance(ir, HighLevelCall)
def detect_unused_return_values(self, f):
"""
@ -47,7 +50,7 @@ contract MyConc{
nodes_origin = {}
for n in f.nodes:
for ir in n.irs:
if isinstance(ir, HighLevelCall):
if self._is_instance(ir):
# if a return value is stored in a state variable, it's ok
if ir.lvalue and not isinstance(ir.lvalue, StateVariable):
values_returned.append(ir.lvalue)
@ -68,15 +71,19 @@ contract MyConc{
continue
unused_return = self.detect_unused_return_values(f)
if unused_return:
info = "{} ({}) does not use the value returned by external calls:\n"
info = info.format(f.canonical_name,
f.source_mapping_str)
for node in unused_return:
info += "\t-{} ({})\n".format(node.expression, node.source_mapping_str)
info = "{} ({}) ignores return value by {} \"{}\" ({})\n"
info = info.format(f.canonical_name,
f.source_mapping_str,
self._txt_description,
node.expression,
node.source_mapping_str)
json = self.generate_json_result(info)
self.add_function_to_json(f, json)
self.add_nodes_to_json(unused_return, json)
results.append(json)
json = self.generate_json_result(info)
self.add_node_to_json(node, json)
self.add_function_to_json(f, json)
results.append(json)
return results

@ -95,27 +95,37 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
info += '\t- {} ({})\n'.format(call_info.expression, call_info.source_mapping_str)
info += '\tState variables written after the call(s):\n'
for (v, node) in sorted(varsWritten, key=lambda x: (x[0].name, x[1].node_id)):
info += '\t- {} ({})\n'.format(v, node.source_mapping_str)
sending_eth_json = []
if calls != send_eth:
sending_eth_json = [{'type' : 'external_calls_sending_eth',
'expression': str(call_info.expression),
'source_mapping': call_info.source_mapping}
for call_info in send_eth]
info += '\t- {} ({})\n'.format(v, node.source_mapping_str)
# Create our JSON result
json = self.generate_json_result(info)
# Add the function with the re-entrancy first
self.add_function_to_json(func, json)
json['elements'] += [{'type': 'external_calls',
'expression': str(call_info.expression),
'source_mapping': call_info.source_mapping}
for call_info in calls]
json['elements'] += sending_eth_json
json['elements'] += [{'type':'variables_written',
'name': v.name,
'expression': str(node.expression),
'source_mapping': node.source_mapping}
for (v, node) in varsWritten]
# Add all underlying calls in the function which are potentially problematic.
for call_info in calls:
self.add_node_to_json(call_info, json, {
"underlying_type": "external_calls"
})
#
# If the calls are not the same ones that send eth, add the eth sending nodes.
if calls != send_eth:
for call_info in send_eth:
self.add_node_to_json(call_info, json, {
"underlying_type": "external_calls_sending_eth"
})
# Add all variables written via nodes which write them.
for (v, node) in varsWritten:
self.add_node_to_json(node, json, {
"underlying_type": "variables_written",
"variable_name": v.name
})
# Append our result
results.append(json)
return results

@ -98,27 +98,37 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m
info += '\t- {} ({})\n'.format(call_info.expression, call_info.source_mapping_str)
info += '\tState variables written after the call(s):\n'
for (v, node) in sorted(varsWritten, key=lambda x: (x[0].name, x[1].node_id)):
info += '\t- {} ({})\n'.format(v, node.source_mapping_str)
sending_eth_json = []
if calls != send_eth:
sending_eth_json = [{'type' : 'external_calls_sending_eth',
'expression': str(call_info.expression),
'source_mapping': call_info.source_mapping}
for call_info in send_eth]
info += '\t- {} ({})\n'.format(v, node.source_mapping_str)
# Create our JSON result
json = self.generate_json_result(info)
# Add the function with the re-entrancy first
self.add_function_to_json(func, json)
json['elements'] += [{'type': 'external_calls',
'expression': str(call_info.expression),
'source_mapping': call_info.source_mapping}
for call_info in calls]
json['elements'] += sending_eth_json
json['elements'] += [{'type':'variables_written',
'name': v.name,
'expression': str(node.expression),
'source_mapping': node.source_mapping}
for (v, node) in varsWritten]
# Add all underlying calls in the function which are potentially problematic.
for call_info in calls:
self.add_node_to_json(call_info, json, {
"underlying_type": "external_calls"
})
#
# If the calls are not the same ones that send eth, add the eth sending nodes.
if calls != send_eth:
for call_info in send_eth:
self.add_node_to_json(call_info, json, {
"underlying_type": "external_calls_sending_eth"
})
# Add all variables written via nodes which write them.
for (v, node) in varsWritten:
self.add_node_to_json(node, json, {
"underlying_type": "variables_written",
"variable_name": v.name
})
# Append our result
results.append(json)
return results

@ -89,22 +89,28 @@ Do not report reentrancies that involve ethers (see `reentrancy-eth`)'''
info += '\t- {} ({})\n'.format(call_info.expression, call_info.source_mapping_str)
info += '\tState variables written after the call(s):\n'
for (v, node) in sorted(varsWritten, key=lambda x: (x[0].name, x[1].node_id)):
info += '\t- {} ({})\n'.format(v, node.source_mapping_str)
sending_eth_json = []
info += '\t- {} ({})\n'.format(v, node.source_mapping_str)
# Create our JSON result
json = self.generate_json_result(info)
# Add the function with the re-entrancy first
self.add_function_to_json(func, json)
json['elements'] += [{'type': 'external_calls',
'expression': str(call_info.expression),
'source_mapping': call_info.source_mapping}
for call_info in calls]
json['elements'] += sending_eth_json
json['elements'] += [{'type':'variables_written',
'name': v.name,
'expression': str(node.expression),
'source_mapping': node.source_mapping}
for (v, node) in varsWritten]
# Add all underlying calls in the function which are potentially problematic.
for call_info in calls:
self.add_node_to_json(call_info, json, {
"underlying_type": "external_calls"
})
# Add all variables written via nodes which write them.
for (v, node) in varsWritten:
self.add_node_to_json(node, json, {
"underlying_type": "variables_written",
"variable_name": v.name
})
# Append our result
results.append(json)
return results

@ -42,7 +42,6 @@ contract Bug {
WIKI_RECOMMENDATION = 'Rename the local variable so as not to mistakenly overshadow any state variable/function/modifier/event definitions.'
OVERSHADOWED_FUNCTION = "function"
OVERSHADOWED_MODIFIER = "modifier"
OVERSHADOWED_STATE_VARIABLE = "state variable"
@ -116,7 +115,6 @@ contract Bug {
overshadowed_entry[0],
overshadowed_entry[2].source_mapping_str)
# Generate relevant JSON data for this shadowing definition.
json = self.generate_json_result(info)
self.add_variable_to_json(local_variable, json)

@ -86,14 +86,12 @@ 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.canonical_name)
info += "\t- {} ({})\n".format(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_function_to_json(func, json)
self.add_nodes_to_json([node], json)
self.add_node_to_json(node, json)
results.append(json)
return results

@ -46,14 +46,14 @@ Bob calls `delegate` and delegates the execution to its malicious contract. As a
continue
nodes = self.controlled_delegatecall(f)
if nodes:
info = '{}.{} ({}) uses delegatecall to a input-controlled function id\n'
info = info.format(contract.name, f.name, f.source_mapping_str)
func_info = '{}.{} ({}) uses delegatecall to a input-controlled function id\n'
func_info = func_info.format(contract.name, f.name, f.source_mapping_str)
for node in nodes:
info += '\t{} ({})\n'.format(node.expression, node.source_mapping_str)
node_info = func_info + '\t- {} ({})\n'.format(node.expression, node.source_mapping_str)
json = self.generate_json_result(info)
self.add_function_to_json(f, json)
self.add_nodes_to_json(nodes, json)
results.append(json)
json = self.generate_json_result(node_info)
self.add_node_to_json(node, json)
self.add_function_to_json(f, json)
results.append(json)
return results

@ -108,21 +108,23 @@ contract Crowdsale{
for c in self.slither.contracts_derived:
ret = self.detect_strict_equality(c)
info = ''
# sort ret to get deterministic results
ret = sorted(list(ret.items()), key=lambda x:x[0].name)
for f, nodes in ret:
info += "{} ({}) uses a dangerous strict equality:\n".format(f.canonical_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)
# Output each node with the function info header as a separate result.
for node in nodes:
info += "\t- {}\n".format(str(node.expression))
node_info = func_info + f"\t- {str(node.expression)}\n"
json = self.generate_json_result(info)
self.add_function_to_json(f, json)
self.add_nodes_to_json(nodes, json)
results.append(json)
json = self.generate_json_result(node_info)
self.add_node_to_json(node, json)
self.add_function_to_json(f, json)
results.append(json)
return results

@ -0,0 +1,78 @@
"""
Module detecting numbers with too many digits.
"""
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.variables import Constant
class TooManyDigits(AbstractDetector):
"""
Detect numbers with too many digits
"""
ARGUMENT = 'too-many-digits'
HELP = 'Conformance to numeric notation best practices'
IMPACT = DetectorClassification.INFORMATIONAL
CONFIDENCE = DetectorClassification.MEDIUM
WIKI = 'https://github.com/crytic/slither/wiki/Detector-Documentation#too-many-digits'
WIKI_TITLE = 'Too many digits'
WIKI_DESCRIPTION = '''
Literals with many digits are difficult to read and review.
'''
WIKI_EXPLOIT_SCENARIO = '''
```solidity
contract MyContract{
uint 1_ether = 10000000000000000000;
}
```
While `1_ether` looks like `1 ether`, it is `10 ether`. As a result, its usage is likely to be incorrect.
'''
WIKI_RECOMMENDATION = '''
Use:
- [Ether suffix](https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#ether-units)
- [Time suffix](https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#time-units), or
- [The scientific notation](https://solidity.readthedocs.io/en/latest/types.html#rational-and-integer-literals)
'''
@staticmethod
def _detect_too_many_digits(f):
ret = []
for node in f.nodes:
# each node contains a list of IR instruction
for ir in node.irs:
# iterate over all the variables read by the IR
for read in ir.read:
# if the variable is a constant
if isinstance(read, Constant):
# read.value can return an int or a str. Convert it to str
value_as_str = read.original_value
line_of_code = str(node.expression)
if '00000' in value_as_str:
# Info to be printed
ret.append(node)
return ret
def _detect(self):
results = []
# iterate over all contracts
for contract in self.slither.contracts_derived:
# iterate over all functions
for f in contract.functions:
# iterate over all the nodes
ret = self._detect_too_many_digits(f)
if ret:
func_info = '{}.{} ({}) uses literals with too many digits:'.format(f.contract.name,
f.name,
f.source_mapping_str)
for node in ret:
node_info = func_info + '\n\t- {}\n'.format(node.expression)
# Add the result in result
json = self.generate_json_result(node_info)
self.add_node_to_json(node, json)
results.append(json)
return results

@ -65,15 +65,14 @@ 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:
info = "{} uses tx.origin for authorization:\n"
info = info.format(func.canonical_name)
for node in nodes:
info += "\t- {} ({})\n".format(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_function_to_json(func, json)
self.add_nodes_to_json(nodes, json)
results.append(json)
json = self.generate_json_result(info)
self.add_node_to_json(node, json)
results.append(json)
return results

@ -67,7 +67,6 @@ class ConstCandidateStateVars(AbstractDetector):
""" Detect state variables that could be const
"""
results = []
all_info = ''
all_variables = [c.state_variables for c in self.slither.contracts]
all_variables = set([item for sublist in all_variables for item in sublist])
@ -84,12 +83,14 @@ class ConstCandidateStateVars(AbstractDetector):
if (not v in all_variables_written) and self._constant_initial_expression(v)]
# Order for deterministic results
constable_variables = sorted(constable_variables, key=lambda x: x.canonical_name)
# Create a result for each finding
for v in constable_variables:
info = "{} should be constant ({})\n".format(v.canonical_name,
v.source_mapping_str)
all_info += info
if all_info != '':
json = self.generate_json_result(all_info)
self.add_variables_to_json(constable_variables, json)
json = self.generate_json_result(info)
self.add_variable_to_json(v, json)
results.append(json)
return results

@ -55,15 +55,15 @@ class UnusedStateVars(AbstractDetector):
for c in self.slither.contracts_derived:
unusedVars = self.detect_unused(c)
if unusedVars:
info = ''
for var in unusedVars:
info += "{} ({}) is never used in {}\n".format(var.canonical_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_variables_to_json(unusedVars, json)
results.append(json)
json = self.generate_json_result(info)
self.add_variable_to_json(var, json)
self.add_contract_to_json(c, json)
results.append(json)
return results

@ -0,0 +1,3 @@
class SlitherException(Exception): pass
class SlitherError(SlitherException): pass

@ -6,7 +6,7 @@ import logging
from slither.printers.abstract_printer import AbstractPrinter
from slither.utils.code_complexity import compute_cyclomatic_complexity
from slither.utils.colors import green, red, yellow
from slither.utils.standard_libraries import is_standard_library
class PrinterHumanSummary(AbstractPrinter):
ARGUMENT = 'human-summary'
@ -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),
@ -88,8 +98,14 @@ class PrinterHumanSummary(AbstractPrinter):
issues_informational, issues_low, issues_medium, issues_high = self._get_detectors_result()
txt = "Number of informational issues: {}\n".format(green(issues_informational))
txt += "Number of low issues: {}\n".format(green(issues_low))
txt += "Number of medium issues: {}\n".format(yellow(issues_medium))
txt += "Number of high issues: {}\n".format(red(issues_high))
if issues_medium > 0:
txt += "Number of medium issues: {}\n".format(yellow(issues_medium))
else:
txt += "Number of medium issues: {}\n".format(green(issues_medium))
if issues_high > 0:
txt += "Number of high issues: {}\n".format(red(issues_high))
else:
txt += "Number of high issues: {}\n\n".format(green(issues_high))
return txt
@ -119,6 +135,49 @@ class PrinterHumanSummary(AbstractPrinter):
def _number_functions(contract):
return len(contract.functions)
def _lines_number(self):
if not self.slither.source_code:
return None
total_dep_lines = 0
total_lines = 0
for filename, source_code in self.slither.source_code.items():
lines = len(source_code.splitlines())
is_dep = False
if self.slither.crytic_compile:
is_dep = self.slither.crytic_compile.is_dependency(filename)
if is_dep:
total_dep_lines += lines
else:
total_lines += lines
return total_lines, total_dep_lines
def _compilation_type(self):
if self.slither.crytic_compile is None:
return 'Compilation non standard\n'
return f'Compiled with {self.slither.crytic_compile.type}\n'
def _number_contracts(self):
if self.slither.crytic_compile is None:
len(self.slither.contracts), 0
deps = [c for c in self.slither.contracts if c.is_from_dependency()]
contracts = [c for c in self.slither.contracts if not c.is_from_dependency()]
return len(contracts), len(deps)
def _standard_libraries(self):
libraries = []
for contract in self.contracts:
lib = is_standard_library(contract)
if lib:
libraries.append(lib)
return libraries
def _ercs(self):
ercs = []
for contract in self.contracts:
ercs += contract.ercs()
return list(set(ercs))
def output(self, _filename):
"""
_filename is not used
@ -126,15 +185,37 @@ class PrinterHumanSummary(AbstractPrinter):
_filename(string)
"""
txt = "Analyze of {}\n".format(self.slither.filename)
txt = "\n"
txt += self._compilation_type()
lines_number = self._lines_number()
if lines_number:
total_lines, total_dep_lines = lines_number
txt += f'Number of lines: {total_lines} (+ {total_dep_lines} in dependencies)\n'
number_contracts, number_contracts_deps = self._number_contracts()
txt += f'Number of contracts: {number_contracts} (+ {number_contracts_deps} in dependencies) \n\n'
txt += self.get_detectors_result()
libs = self._standard_libraries()
if libs:
txt += f'\nUse: {", ".join(libs)}\n'
ercs = self._ercs()
if ercs:
txt += f'ERCs: {", ".join(ercs)}\n'
for contract in self.slither.contracts_derived:
txt += "\nContract {}\n".format(contract.name)
txt += self.is_complex_code(contract)
txt += '\tNumber of functions: {}\n'.format(self._number_functions(contract))
ercs = contract.ercs()
if ercs:
txt += '\tERCs: ' + ','.join(ercs) + '\n'
is_erc20 = contract.is_erc20()
txt += '\tNumber of functions:{}'.format(self._number_functions(contract))
txt += "\tIs ERC20 token: {}\n".format(contract.is_erc20())
if is_erc20:
txt += '\tERC20 info:\n'
txt += self.get_summary_erc20(contract)
self.info(txt)

@ -11,7 +11,7 @@ from crytic_compile import CryticCompile, InvalidCompilation
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.printers.abstract_printer import AbstractPrinter
from .solc_parsing.slitherSolc import SlitherSolc
from .utils.colors import red
from .exceptions import SlitherError
logger = logging.getLogger("Slither")
logging.basicConfig()
@ -44,10 +44,6 @@ class Slither(SlitherSolc):
embark_overwrite_config (bool): overwrite original config file (default false)
'''
truffle_ignore = kwargs.get('truffle_ignore', False)
embark_ignore = kwargs.get('embark_ignore', False)
# list of files provided (see --splitted option)
if isinstance(contract, list):
self._init_from_list(contract)
@ -56,17 +52,13 @@ class Slither(SlitherSolc):
else:
super(Slither, self).__init__('')
try:
cryticCompile = CryticCompile(contract, **kwargs)
self._crytic_compile = cryticCompile
crytic_compile = CryticCompile(contract, **kwargs)
self._crytic_compile = crytic_compile
except InvalidCompilation as e:
logger.error('Invalid compilation')
logger.error(e)
exit(-1)
for path, ast in cryticCompile.asts.items():
raise SlitherError('Invalid compilation: \n'+str(e))
for path, ast in crytic_compile.asts.items():
self._parse_contracts_from_loaded_json(ast, path)
with open(path) as f:
self.source_code[path] = f.read()
self._add_source_code(path)
self._detectors = []
self._printers = []
@ -82,14 +74,12 @@ class Slither(SlitherSolc):
def _init_from_raw_json(self, filename):
if not os.path.isfile(filename):
logger.error('{} does not exist (are you in the correct directory?)'.format(filename))
exit(-1)
raise SlitherError('{} does not exist (are you in the correct directory?)'.format(filename))
assert filename.endswith('json')
with open(filename, encoding='utf8') as astFile:
stdout = astFile.read()
if not stdout:
logger.info('Empty AST file: %s', filename)
sys.exit(-1)
raise SlitherError('Empty AST file: %s', filename)
contracts_json = stdout.split('\n=')
super(Slither, self).__init__(filename)
@ -170,21 +160,19 @@ class Slither(SlitherSolc):
)
)
if any(isinstance(obj, cls) for obj in instances_list):
if any(type(obj) == cls for obj in instances_list):
raise Exception(
"You can't register {!r} twice.".format(cls)
)
def _run_solc(self, filename, solc, disable_solc_warnings, solc_arguments, ast_format):
if not os.path.isfile(filename):
logger.error('{} does not exist (are you in the correct directory?)'.format(filename))
exit(-1)
raise SlitherError('{} does not exist (are you in the correct directory?)'.format(filename))
assert filename.endswith('json')
with open(filename, encoding='utf8') as astFile:
stdout = astFile.read()
if not stdout:
logger.info('Empty AST file: %s', filename)
sys.exit(-1)
raise SlitherError('Empty AST file: %s', filename)
stdout = stdout.split('\n=')
return stdout

@ -6,8 +6,11 @@ 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
from slither.slithir.variables import TupleVariable
from slither.slithir.operations import (Assignment, Balance, Binary,
BinaryType, Call, Condition, Delete,
EventCall, HighLevelCall, Index,
@ -30,6 +33,8 @@ from slither.slithir.variables import (Constant, ReferenceVariable,
TemporaryVariable)
from slither.visitors.slithir.expression_to_slithir import ExpressionToSlithIR
from slither.utils.function import get_function_id
from slither.utils.type import export_nested_types_from_variable
from slither.slithir.exceptions import SlithIRError
logger = logging.getLogger('ConvertToIR')
@ -39,7 +44,8 @@ def convert_expression(expression, node):
from slither.core.cfg.node import NodeType
if isinstance(expression, Literal) and node.type in [NodeType.IF, NodeType.IFLOOP]:
result = [Condition(Constant(expression.value))]
cst = Constant(expression.value, expression.type)
result = [Condition(cst)]
return result
if isinstance(expression, Identifier) and node.type in [NodeType.IF, NodeType.IFLOOP]:
result = [Condition(expression.value)]
@ -306,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
@ -353,7 +397,7 @@ def propagate_types(ir, node):
# Convert push operations
# May need to insert a new operation
# Which leads to return a list of operation
if isinstance(t, ArrayType):
if isinstance(t, ArrayType) or (isinstance(t, ElementaryType) and t.type == 'bytes'):
if ir.function_name == 'push' and len(ir.arguments) == 1:
return convert_to_push(ir, node)
@ -407,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)):
@ -435,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):
@ -450,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])
@ -468,8 +522,7 @@ def propagate_types(ir, node):
# temporary operation; they will be removed
pass
else:
logger.error('Not handling {} during type propgation'.format(type(ir)))
exit(-1)
raise SlithIRError('Not handling {} during type propgation'.format(type(ir)))
def extract_tmp_call(ins, contract):
assert isinstance(ins, TmpCall)
@ -588,8 +641,7 @@ def convert_to_low_level(ir):
new_ir.arguments = ir.arguments
new_ir.lvalue.set_type(ElementaryType('bool'))
return new_ir
logger.error('Incorrect conversion to low level {}'.format(ir))
exit(-1)
raise SlithIRError('Incorrect conversion to low level {}'.format(ir))
def convert_to_push(ir, node):
"""
@ -614,7 +666,7 @@ def convert_to_push(ir, node):
ir = Push(ir.destination, val)
length = Literal(len(operation.init_values))
length = Literal(len(operation.init_values), 'uint256')
t = operation.init_values[0].type
ir.lvalue.set_type(ArrayType(t, length))
@ -693,6 +745,9 @@ def convert_type_library_call(ir, lib_contract):
func = lib_contract.get_function_from_signature(sig)
if not func:
func = lib_contract.get_state_variable_from_name(ir.function_name)
if func:
# stop to explore if func is found (prevent dupplicate issue)
break
# In case of multiple binding to the same type
if not func:
# specific lookup when the compiler does implicit conversion
@ -728,6 +783,9 @@ def convert_type_of_high_and_internal_level_call(ir, contract):
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)
@ -735,6 +793,9 @@ def convert_type_of_high_and_internal_level_call(ir, contract):
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
@ -848,6 +909,80 @@ def remove_unused(result):
result = [i for i in result if not i in to_remove]
return result
# endregion
###################################################################################
###################################################################################
# region Constant type conversioh
###################################################################################
###################################################################################
def convert_constant_types(irs):
"""
late conversion of uint -> type for constant (Literal)
:param irs:
:return:
"""
# TODO: implement instances lookup for events, NewContract
was_changed = True
while was_changed:
was_changed = False
for ir in irs:
if isinstance(ir, Assignment):
if isinstance(ir.lvalue.type, ElementaryType):
if ir.lvalue.type.type in ElementaryTypeInt:
if isinstance(ir.rvalue, Function):
continue
elif isinstance(ir.rvalue, TupleVariable):
# TODO: fix missing Unpack conversion
continue
else:
if ir.rvalue.type.type != 'int256':
ir.rvalue.set_type(ElementaryType('int256'))
was_changed = True
if isinstance(ir, Binary):
if isinstance(ir.lvalue.type, ElementaryType):
if ir.lvalue.type.type in ElementaryTypeInt:
for r in ir.read:
if r.type.type != 'int256':
r.set_type(ElementaryType('int256'))
was_changed = True
if isinstance(ir, (HighLevelCall, InternalCall)):
func = ir.function
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]
if isinstance(t, ElementaryType):
if t.type in ElementaryTypeInt:
if arg.type.type != 'int256':
arg.set_type(ElementaryType('int256'))
was_changed = True
if isinstance(ir, NewStructure):
st = ir.structure
for idx, arg in enumerate(ir.arguments):
e = st.elems_ordered[idx]
if isinstance(e.type, ElementaryType):
if e.type.type in ElementaryTypeInt:
if arg.type.type != 'int256':
arg.set_type(ElementaryType('int256'))
was_changed = True
if isinstance(ir, InitArray):
if isinstance(ir.lvalue.type, ArrayType):
if isinstance(ir.lvalue.type.type, ElementaryType):
if ir.lvalue.type.type.type in ElementaryTypeInt:
for r in ir.read:
if r.type.type != 'int256':
r.set_type(ElementaryType('int256'))
was_changed = True
# endregion
###################################################################################
###################################################################################
@ -865,6 +1000,7 @@ def apply_ir_heuristics(irs, node):
irs = propagate_type_and_convert_call(irs, node)
irs = remove_unused(irs)
find_references_origin(irs)
convert_constant_types(irs)
return irs

@ -0,0 +1,3 @@
from slither.exceptions import SlitherException
class SlithIRError(SlitherException): pass

@ -4,6 +4,7 @@ from slither.core.variables.variable import Variable
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue
from slither.core.solidity_types import ElementaryType
from slither.slithir.variables import ReferenceVariable
from slither.slithir.exceptions import SlithIRError
logger = logging.getLogger("BinaryOperationIR")
@ -80,8 +81,7 @@ class BinaryType(object):
if operation_type == '||':
return BinaryType.OROR
logger.error('get_type: Unknown operation type {})'.format(operation_type))
exit(-1)
raise SlithIRError('get_type: Unknown operation type {})'.format(operation_type))
@staticmethod
def str(operation_type):
@ -123,8 +123,7 @@ class BinaryType(object):
return '&&'
if operation_type == BinaryType.OROR:
return '||'
logger.error('str: Unknown operation type {})'.format(operation_type))
exit(-1)
raise SlithIRError('str: Unknown operation type {})'.format(operation_type))
class Binary(OperationWithLValue):

@ -40,7 +40,7 @@ class Return(Operation):
@property
def values(self):
return self._values
return self._unroll(self._values)
def __str__(self):
return "RETURN {}".format(','.join(['{}'.format(x) for x in self.values]))

@ -1,8 +1,7 @@
import logging
from slither.slithir.operations.lvalue import OperationWithLValue
from slither.core.variables.variable import Variable
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue
from slither.slithir.exceptions import SlithIRError
logger = logging.getLogger("BinaryOperationIR")
@ -17,8 +16,7 @@ class UnaryType:
return UnaryType.BANG
if operation_type == '~':
return UnaryType.TILD
logger.error('get_type: Unknown operation type {}'.format(operation_type))
exit(-1)
raise SlithIRError('get_type: Unknown operation type {}'.format(operation_type))
@staticmethod
def str(operation_type):
@ -27,8 +25,7 @@ class UnaryType:
if operation_type == UnaryType.TILD:
return '~'
logger.error('str: Unknown operation type {}'.format(operation_type))
exit(-1)
raise SlithIRError('str: Unknown operation type {}'.format(operation_type))
class Unary(OperationWithLValue):

@ -22,6 +22,7 @@ from slither.slithir.variables import (Constant, LocalIRVariable,
ReferenceVariable, ReferenceVariableSSA,
StateIRVariable, TemporaryVariable,
TemporaryVariableSSA, TupleVariable, TupleVariableSSA)
from slither.slithir.exceptions import SlithIRError
logger = logging.getLogger('SSA_Conversion')
@ -662,7 +663,6 @@ def copy_ir(ir, *instances):
return Length(value, lvalue)
logger.error('Impossible ir copy on {} ({})'.format(ir, type(ir)))
exit(-1)
raise SlithIRError('Impossible ir copy on {} ({})'.format(ir, type(ir)))
# endregion

@ -1,17 +1,41 @@
from .variable import SlithIRVariable
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint
class Constant(SlithIRVariable):
def __init__(self, val):
def __init__(self, val, type=None):
super(Constant, self).__init__()
assert isinstance(val, str)
if val.isdigit():
self._type = ElementaryType('uint256')
self._val = int(val)
self._original_value = val
if type:
assert isinstance(type, ElementaryType)
self._type = type
if type.type in Int + Uint + ['address']:
if val.startswith('0x') or val.startswith('0X'):
self._val = int(val, 16)
else:
if 'e' in val:
base, expo = val.split('e')
self._val = int(float(base)* (10 ** int(expo)))
elif 'E' in val:
base, expo = val.split('E')
self._val = int(float(base) * (10 ** int(expo)))
else:
self._val = int(float(val))
elif type.type == 'bool':
self._val = val == 'true'
else:
self._val = val
else:
self._type = ElementaryType('string')
self._val = val
if val.isdigit():
self._type = ElementaryType('uint256')
self._val = int(val)
else:
self._type = ElementaryType('string')
self._val = val
@property
def value(self):
@ -20,10 +44,18 @@ class Constant(SlithIRVariable):
If the expression was an hexadecimal delcared as hex'...'
return a str
Returns:
(str, int)
(str | int | bool)
'''
return self._val
@property
def original_value(self):
'''
Return the string representation of the value
:return: str
'''
return self._original_value
def __str__(self):
return str(self.value)

@ -9,6 +9,7 @@ from slither.solc_parsing.declarations.modifier import ModifierSolc
from slither.solc_parsing.declarations.structure import StructureSolc
from slither.solc_parsing.solidity_types.type_parsing import parse_type
from slither.solc_parsing.variables.state_variable import StateVariableSolc
from slither.solc_parsing.exceptions import ParsingError
logger = logging.getLogger("ContractSolcParsing")
@ -186,8 +187,7 @@ class ContractSolc04(Contract):
elif item[self.get_key()] == 'UsingForDirective':
self._usingForNotParsed.append(item)
else:
logger.error('Unknown contract item: '+item[self.get_key()])
exit(-1)
raise ParsingError('Unknown contract item: '+item[self.get_key()])
return
def _parse_struct(self, struct):

@ -26,6 +26,7 @@ from slither.utils.expression_manipulations import SplitTernaryExpression
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
logger = logging.getLogger("FunctionSolc")
@ -726,8 +727,7 @@ class FunctionSolc(Function):
link_nodes(node, new_node)
node = new_node
else:
logger.error('Statement not parsed %s'%name)
exit(-1)
raise ParsingError('Statement not parsed %s'%name)
return node
@ -815,8 +815,7 @@ class FunctionSolc(Function):
end_node = self._find_end_loop(node, [], 0)
if not end_node:
logger.error('Break in no-loop context {}'.format(node))
exit(-1)
raise ParsingError('Break in no-loop context {}'.format(node))
for son in node.sons:
son.remove_father(node)
@ -827,8 +826,7 @@ class FunctionSolc(Function):
start_node = self._find_start_loop(node, [])
if not start_node:
logger.error('Continue in no-loop context {}'.format(node.nodeId()))
exit(-1)
raise ParsingError('Continue in no-loop context {}'.format(node.nodeId()))
for son in node.sons:
son.remove_father(node)

@ -16,6 +16,7 @@ class StructureSolc(Structure):
self._name = name
self._canonical_name = canonicalName
self._elems = {}
self._elems_ordered = []
self._elemsNotParsed = elems
@ -28,5 +29,6 @@ class StructureSolc(Structure):
elem.analyze(self.contract)
self._elems[elem.name] = elem
self._elems_ordered.append(elem.name)
self._elemsNotParsed = []

@ -0,0 +1,9 @@
from slither.exceptions import SlitherException
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, VariableNotFound
logger = logging.getLogger("ExpressionParsing")
###################################################################################
###################################################################################
# region Exception
###################################################################################
###################################################################################
class VariableNotFound(Exception): pass
# endregion
###################################################################################
###################################################################################
# region Helpers
@ -94,8 +86,7 @@ def find_variable(var_name, caller_context, referenced_declaration=None, is_supe
contract = function.contract
contract_declarer = function.contract_declarer
else:
logger.error('Incorrect caller context')
exit(-1)
raise ParsingError('Incorrect caller context')
if function:
# We look for variable declared with the referencedDeclaration attr
@ -185,7 +176,7 @@ def find_variable(var_name, caller_context, referenced_declaration=None, is_supe
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
###################################################################################
@ -506,6 +497,12 @@ def parse_expression(expression, caller_context):
value = str(convert_subdenomination(value, expression['subdenomination']))
elif not value and value != "":
value = '0x'+expression['hexValue']
type = expression['typeDescriptions']['typeString']
# Length declaration for array was None until solc 0.5.5
if type is None:
if expression['kind'] == 'number':
type = 'int_const'
else:
value = expression['attributes']['value']
if value:
@ -516,7 +513,22 @@ def parse_expression(expression, caller_context):
# see https://solidity.readthedocs.io/en/v0.4.25/types.html?highlight=hex#hexadecimal-literals
assert 'hexvalue' in expression['attributes']
value = '0x'+expression['attributes']['hexvalue']
literal = Literal(value)
type = expression['attributes']['type']
if type is None:
if value.isdecimal():
type = ElementaryType('uint256')
else:
type = ElementaryType('string')
elif type.startswith('int_const '):
type = ElementaryType('uint256')
elif type.startswith('bool'):
type = ElementaryType('bool')
elif type.startswith('address'):
type = ElementaryType('address')
else:
type = ElementaryType('string')
literal = Literal(value, type)
return literal
elif name == 'Identifier':
@ -630,8 +642,7 @@ def parse_expression(expression, caller_context):
elif type_name[caller_context.get_key()] == 'FunctionTypeName':
array_type = parse_type(type_name, caller_context)
else:
logger.error('Incorrect type array {}'.format(type_name))
exit(-1)
raise ParsingError('Incorrect type array {}'.format(type_name))
array = NewArray(depth, array_type)
return array
@ -667,5 +678,5 @@ def parse_expression(expression, caller_context):
call = CallExpression(called, arguments, 'Modifier')
return call
logger.error('Expression not parsed %s'%name)
exit(-1)
raise ParsingError('Expression not parsed %s'%name)

@ -14,6 +14,7 @@ from slither.core.declarations.import_directive import Import
from slither.analyses.data_dependency.data_dependency import compute_dependency
from slither.utils.colors import red
from .exceptions import ParsingNameReuse, ParsingContractNotFound
class SlitherSolc(Slither):
@ -89,9 +90,7 @@ class SlitherSolc(Slither):
if 'sourcePaths' in data_loaded:
for sourcePath in data_loaded['sourcePaths']:
if os.path.isfile(sourcePath):
with open(sourcePath, encoding='utf8', newline='') as f:
source_code = f.read()
self.source_code[sourcePath] = source_code
self._add_source_code(sourcePath)
if data_loaded[self.get_key()] == 'root':
self._solc_version = '0.3'
@ -137,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]
@ -149,18 +148,22 @@ 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:
with open(name, encoding='utf8', newline='') as f:
source_code = f.read()
self.source_code[name] = source_code
self._add_source_code(name)
else:
lib_name = os.path.join('node_modules', name)
if os.path.isfile(lib_name) and not name in self.source_code:
with open(lib_name, encoding='utf8', newline='') as f:
source_code = f.read()
self.source_code[name] = source_code
self._add_source_code(lib_name)
# endregion
###################################################################################
@ -188,8 +191,7 @@ class SlitherSolc(Slither):
info += '\n{} is defined in:'.format(contract.name)
info += '\n- {}\n- {}'.format(contract.source_mapping_str,
self._contracts[contract.name].source_mapping_str)
logger.error(info)
exit(-1)
raise ParsingNameReuse(info)
else:
self._contracts_by_id[contract.id] = contract
self._contracts[contract.name] = contract
@ -223,11 +225,11 @@ class SlitherSolc(Slither):
father_constructors.append(self._contracts_by_id[i])
except KeyError:
logger.error(red('A contract was not found, it is likely that your codebase contains muliple contracts with the same name'))
logger.error(red('Truffle does not handle this case during compilation'))
logger.error(red('Please read https://github.com/trailofbits/slither/wiki#keyerror-or-nonetype-error'))
logger.error(red('And update your code to remove the duplicate'))
exit(-1)
txt = 'A contract was not found, it is likely that your codebase contains muliple contracts with the same name'
txt += 'Truffle does not handle this case during compilation'
txt += 'Please read https://github.com/trailofbits/slither/wiki#keyerror-or-nonetype-error'
txt += 'And update your code to remove the duplicate'
raise ParsingContractNotFound(txt)
contract.setInheritance(ancestors, fathers, father_constructors)
contracts_to_be_analyzed = self.contracts

@ -13,6 +13,7 @@ from slither.core.declarations.function import Function
from slither.core.expressions.literal import Literal
from slither.solc_parsing.exceptions import ParsingError
import re
logger = logging.getLogger('TypeParsing')
@ -32,7 +33,7 @@ def _find_from_type_name(name, contract, contracts, structures, enums):
if name_elementary in ElementaryTypeName:
depth = name.count('[')
if depth:
return ArrayType(ElementaryType(name_elementary), Literal(depth))
return ArrayType(ElementaryType(name_elementary), Literal(depth, 'uint256'))
else:
return ElementaryType(name_elementary)
# We first look for contract
@ -78,7 +79,7 @@ def _find_from_type_name(name, contract, contracts, structures, enums):
depth+=1
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))
return ArrayType(UserDefinedType(var_type), Literal(depth, 'uint256'))
if not var_type:
var_type = next((f for f in contract.functions if f.name == name), None)
@ -118,8 +119,7 @@ def _find_from_type_name(name, contract, contracts, structures, enums):
return MappingType(from_type, to_type)
if not var_type:
logger.error('Type not found '+str(name))
exit(-1)
raise ParsingError('Type not found '+str(name))
return UserDefinedType(var_type)
@ -134,8 +134,7 @@ def parse_type(t, caller_context):
elif isinstance(caller_context, Function):
contract = caller_context.contract
else:
logger.error('Incorrect caller context')
exit(-1)
raise ParsingError('Incorrect caller context')
is_compact_ast = caller_context.is_compact_ast
@ -223,5 +222,4 @@ def parse_type(t, caller_context):
return FunctionType(params_vars, return_values_vars)
logger.error('Type name not found '+str(t))
exit(-1)
raise ParsingError('Type name not found '+str(t))

@ -6,7 +6,7 @@ from slither.core.variables.variable import Variable
from slither.solc_parsing.solidity_types.type_parsing import parse_type, UnknownType
from slither.core.solidity_types.elementary_type import ElementaryType, NonElementaryType
from slither.solc_parsing.exceptions import ParsingError
logger = logging.getLogger("VariableDeclarationSolcParsing")
class MultipleVariablesDeclaration(Exception):
@ -51,8 +51,7 @@ class VariableDeclarationSolc(Variable):
elif nodeType == 'VariableDeclaration':
self._init_from_declaration(var, var['value'])
else:
logger.error('Incorrect variable declaration type {}'.format(nodeType))
exit(-1)
raise ParsingError('Incorrect variable declaration type {}'.format(nodeType))
else:
nodeType = var['name']
@ -65,15 +64,13 @@ class VariableDeclarationSolc(Variable):
elif len(var['children']) > 2:
raise MultipleVariablesDeclaration
else:
logger.error('Variable declaration without children?'+var)
exit(-1)
raise ParsingError('Variable declaration without children?'+var)
declaration = var['children'][0]
self._init_from_declaration(declaration, init)
elif nodeType == 'VariableDeclaration':
self._init_from_declaration(var, None)
else:
logger.error('Incorrect variable declaration type {}'.format(nodeType))
exit(-1)
raise ParsingError('Incorrect variable declaration type {}'.format(nodeType))
@property
def initialized(self):

@ -0,0 +1,69 @@
def erc_to_signatures(erc):
return [f'{e[0]}({",".join(e[1])})' for e in erc]
# Final
# https://eips.ethereum.org/EIPS/eip-20
# name, symbolc, decimals are optionals
ERC20 = [('totalSupply', [], 'uint256'),
('balanceOf', ['address'], 'uint256'),
('transfer', ['address', 'uint256'], 'bool'),
('transferFrom', ['address', 'address', 'uint256'], 'bool'),
('approve', ['address', 'uint256'], 'bool'),
('allowance', ['address', 'address'], 'uint256')]
ERC20_signatures = erc_to_signatures(ERC20)
# Draft
# https://github.com/ethereum/eips/issues/223
ERC223 = [('name', [], 'string'),
('symbol', [], 'string'),
('decimals', [], 'uint8'),
('totalSupply', [], 'uint256'),
('balanceOf', ['address'], 'uint256'),
('transfer', ['address', 'uint256'], 'bool'),
('transfer', ['address', 'uint256', 'bytes'], 'bool'),
('transfer', ['address', 'uint256', 'bytes', 'string'], 'bool')]
ERC223_signatures = erc_to_signatures(ERC223)
# Final
# https://eips.ethereum.org/EIPS/eip-165
ERC165 = [('supportsInterface', ['bytes4'], 'bool')]
ERC165_signatures = erc_to_signatures(ERC165)
# Final
# https://eips.ethereum.org/EIPS/eip-721
# Must have ERC165
# name, symbol, tokenURI are optionals
ERC721 = [('balanceOf', ['address'], 'uint256'),
('ownerOf', ['uint256'], 'address'),
('safeTransferFrom', ['address', 'address', 'uint256', 'bytes'], ''),
('safeTransferFrom', ['address', 'address', 'uint256'], ''),
('transferFrom', ['address', 'address', 'uint256'], ''),
('approve', ['address', 'uint256'], ''),
('setApprovalForAll', ['address', 'bool'], ''),
('getApproved', ['uint256'], 'address'),
('isApprovedForAll', ['address', 'address'], 'bool')] + ERC165
ERC721_signatures = erc_to_signatures(ERC721)
# Final
# https://eips.ethereum.org/EIPS/eip-1820
ERC1820 = [('canImplementInterfaceForAddress', ['bytes32', 'address'], 'bytes32')]
ERC1820_signatures = erc_to_signatures(ERC1820)
# Last Call
# https://eips.ethereum.org/EIPS/eip-777
ERC777 = [('name', [], 'string'),
('symbol', [], 'string'),
('totalSupply', [], 'uint256'),
('balanceOf', ['address'], 'uint256'),
('granularity', [], 'uint256'),
('defaultOperators', [], 'address[]'),
('isOperatorFor', ['address', 'address'], 'bool'),
('authorizeOperator', ['address'], ''),
('revokeOperator', ['address'], ''),
('send', ['address', 'uint256', 'bytes'], ''),
('operatorSend', ['address', 'address', 'uint256', 'bytes', 'bytes'], ''),
('burn', ['uint256', 'bytes'] , ''),
('operatorBurn', ['address', 'uint256', 'bytes', 'bytes'] , '')]
ERC777_signatures = erc_to_signatures(ERC777)

@ -0,0 +1,193 @@
from pathlib import Path
libraries = {
'Openzeppelin-SafeMath': lambda x: is_openzepellin_safemath(x),
'Openzeppelin-ECRecovery': lambda x: is_openzepellin_ecrecovery(x),
'Openzeppelin-Ownable': lambda x: is_openzepellin_ownable(x),
'Openzeppelin-ERC20': lambda x: is_openzepellin_erc20(x),
'Openzeppelin-ERC721': lambda x: is_openzepellin_erc721(x),
'Zos-Upgrade': lambda x: is_zos_initializable(x),
'Dapphub-DSAuth': lambda x: is_dapphub_ds_auth(x),
'Dapphub-DSMath': lambda x: is_dapphub_ds_math(x),
'Dapphub-DSToken': lambda x: is_dapphub_ds_token(x),
'Dapphub-DSProxy': lambda x: is_dapphub_ds_proxy(x),
'Dapphub-DSGroup': lambda x: is_dapphub_ds_group(x),
}
def is_standard_library(contract):
for name, is_lib in libraries.items():
if is_lib(contract):
return name
return None
###################################################################################
###################################################################################
# region General libraries
###################################################################################
###################################################################################
def is_openzepellin(contract):
if not contract.is_from_dependency():
return False
return 'openzeppelin-solidity' in Path(contract.source_mapping['filename_absolute']).parts
def is_zos(contract):
if not contract.is_from_dependency():
return False
return 'zos-lib' in Path(contract.source_mapping['filename_absolute']).parts
# endregion
###################################################################################
###################################################################################
# region SafeMath
###################################################################################
###################################################################################
def is_safemath(contract):
return contract.name == "SafeMath"
def is_openzepellin_safemath(contract):
return is_safemath(contract) and is_openzepellin(contract)
# endregion
###################################################################################
###################################################################################
# region ECRecovery
###################################################################################
###################################################################################
def is_ecrecovery(contract):
return contract.name == 'ECRecovery'
def is_openzepellin_ecrecovery(contract):
return is_ecrecovery(contract) and is_openzepellin(contract)
# endregion
###################################################################################
###################################################################################
# region Ownable
###################################################################################
###################################################################################
def is_ownable(contract):
return contract.name == 'Ownable'
def is_openzepellin_ownable(contract):
return is_ownable(contract) and is_openzepellin(contract)
# endregion
###################################################################################
###################################################################################
# region ERC20
###################################################################################
###################################################################################
def is_erc20(contract):
return contract.name == 'ERC20'
def is_openzepellin_erc20(contract):
return is_erc20(contract) and is_openzepellin(contract)
# endregion
###################################################################################
###################################################################################
# region ERC721
###################################################################################
###################################################################################
def is_erc721(contract):
return contract.name == 'ERC721'
def is_openzepellin_erc721(contract):
return is_erc721(contract) and is_openzepellin(contract)
# endregion
###################################################################################
###################################################################################
# region Zos Initializable
###################################################################################
###################################################################################
def is_initializable(contract):
return contract.name == 'Initializable'
def is_zos_initializable(contract):
return is_initializable(contract) and is_zos(contract)
# endregion
###################################################################################
###################################################################################
# region DappHub
###################################################################################
###################################################################################
dapphubs = {
'DSAuth': 'ds-auth',
'DSMath': 'ds-math',
'DSToken': 'ds-token',
'DSProxy': 'ds-proxy',
'DSGroup': 'ds-group',
}
def _is_ds(contract, name):
return contract.name == name
def _is_dappdhub_ds(contract, name):
if not contract.is_from_dependency():
return False
if not dapphubs[name] in Path(contract.source_mapping['filename_absolute']).parts:
return False
return _is_ds(contract, name)
def is_ds_auth(contract):
return _is_ds(contract, 'DSAuth')
def is_dapphub_ds_auth(contract):
return _is_dappdhub_ds(contract, 'DSAuth')
def is_ds_math(contract):
return _is_ds(contract, 'DSMath')
def is_dapphub_ds_math(contract):
return _is_dappdhub_ds(contract, 'DSMath')
def is_ds_token(contract):
return _is_ds(contract, 'DSToken')
def is_dapphub_ds_token(contract):
return _is_dappdhub_ds(contract, 'DSToken')
def is_ds_proxy(contract):
return _is_ds(contract, 'DSProxy')
def is_dapphub_ds_proxy(contract):
return _is_dappdhub_ds(contract, 'DSProxy')
def is_ds_group(contract):
return _is_ds(contract, 'DSGroup')
def is_dapphub_ds_group(contract):
return _is_dappdhub_ds(contract, 'DSGroup')

@ -0,0 +1,34 @@
from slither.core.solidity_types import (ArrayType, MappingType, ElementaryType)
def _add_mapping_parameter(t, l):
while isinstance(t, MappingType):
l.append(t.type_from)
t = t.type_to
_add_array_parameter(t, l)
def _add_array_parameter(t, l):
while isinstance(t, ArrayType):
l.append(ElementaryType('uint256'))
t = t.type
def export_nested_types_from_variable(variable):
"""
Export the list of nested types (mapping/array)
:param variable:
:return: list(Type)
"""
l = []
if isinstance(variable.type, MappingType):
t = variable.type
_add_mapping_parameter(t, l)
if isinstance(variable.type, ArrayType):
v = variable
_add_array_parameter(v.type, l)
return l

@ -20,8 +20,12 @@ def set_val(expression, val):
class ConstantFolding(ExpressionVisitor):
def __init__(self, expression, type):
self._type = type
super(ConstantFolding, self).__init__(expression)
def result(self):
return Literal(int(get_val(self._expression)))
return Literal(int(get_val(self._expression)), self._type)
def _post_identifier(self, expression):
if not expression.value.is_constant:
@ -29,7 +33,7 @@ class ConstantFolding(ExpressionVisitor):
expr = expression.value.expression
# assumption that we won't have infinite loop
if not isinstance(expr, Literal):
cf = ConstantFolding(expr)
cf = ConstantFolding(expr, self._type)
expr = cf.result()
set_val(expression, int(expr.value))

@ -15,12 +15,14 @@ from slither.core.expressions.new_elementary_type import NewElementaryType
from slither.core.expressions.tuple_expression import TupleExpression
from slither.core.expressions.type_conversion import TypeConversion
from slither.core.expressions.unary_operation import UnaryOperation
from slither.exceptions import SlitherError
logger = logging.getLogger("ExpressionVisitor")
class ExpressionVisitor:
def __init__(self, expression):
# Inherited class must declared their variables prior calling super().__init__
self._expression = expression
self._result = None
self._visit_expression(self.expression)
@ -86,8 +88,7 @@ class ExpressionVisitor:
pass
else:
logger.error('Expression not handled: {}'.format(expression))
exit(-1)
raise SlitherError('Expression not handled: {}'.format(expression))
self._post_visit(expression)
@ -200,8 +201,7 @@ class ExpressionVisitor:
pass
else:
logger.error('Expression not handled: {}'.format(expression))
exit(-1)
raise SlitherError('Expression not handled: {}'.format(expression))
# pre_expression_name
@ -302,8 +302,7 @@ class ExpressionVisitor:
pass
else:
logger.error('Expression not handled: {}'.format(expression))
exit(-1)
raise SlitherError('Expression not handled: {}'.format(expression))
# post_expression_name

@ -17,8 +17,7 @@ from slither.slithir.variables import (Constant, ReferenceVariable,
TemporaryVariable, TupleVariable)
from slither.visitors.expression.expression import ExpressionVisitor
#from slither.slithir.variables.state_variable import StateIRVariable
#from slither.slithir.variables.local_variable import LocalIRVariable
from slither.slithir.exceptions import SlithIRError
logger = logging.getLogger("VISTIOR:ExpressionToSlithIR")
@ -57,8 +56,7 @@ def convert_assignment(left, right, t, return_type):
elif t == AssignmentOperationType.ASSIGN_MODULO:
return Binary(left, left, right, BinaryType.MODULO)
logger.error('Missing type during assignment conversion')
exit(-1)
raise SlithIRError('Missing type during assignment conversion')
class ExpressionToSlithIR(ExpressionVisitor):
@ -173,7 +171,8 @@ class ExpressionToSlithIR(ExpressionVisitor):
set_val(expression, val)
def _post_literal(self, expression):
set_val(expression, Constant(expression.value))
cst = Constant(expression.value, expression.type)
set_val(expression, cst)
def _post_member_access(self, expression):
expr = get(expression.expression)

@ -1,204 +1,378 @@
[
{
"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": [
{
"success": true,
"error": null,
"results": {
"detectors": [
{
"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
"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
},
"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": "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
},
"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": "expression",
"expression": "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
}
}
]
},
{
"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",
"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
"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
},
"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()"
}
}
}
}
}
},
{
"type": "expression",
"expression": "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
}
]
}
]
}
]
}

@ -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,204 +1,378 @@
[
{
"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": [
{
"success": true,
"error": null,
"results": {
"detectors": [
{
"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
"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
},
"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": "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
},
"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": "expression",
"expression": "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
}
}
]
},
{
"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",
"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
"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
},
"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()"
}
}
}
}
}
},
{
"type": "expression",
"expression": "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
}
]
}
]
}
]
}

@ -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,52 +1,61 @@
[
{
"check": "backdoor",
"impact": "High",
"confidence": "High",
"description": "Backdoor function found in C.i_am_a_backdoor (tests/backdoor.sol#4-6)\n",
"elements": [
{
"success": true,
"error": null,
"results": {
"detectors": [
{
"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",
"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
"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
},
"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:
Backdoor function found in C.i_am_a_backdoor (tests/backdoor.sol#4-6)
Reference: https://github.com/trailofbits/slither/wiki/Adding-a-new-detector
INFO:Slither:/home/monty/Private/tob/tools/slither-public/scripts/../tests/expected_json/backdoor.backdoor.json exists already, the overwrite is prevented
INFO:Slither:/home/travis/build/crytic/slither/scripts/../tests/expected_json/backdoor.backdoor.json exists already, the overwrite is prevented
INFO:Slither:tests/backdoor.sol analyzed (1 contracts), 1 result(s) found

@ -1,52 +1,61 @@
[
{
"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": [
{
"success": true,
"error": null,
"results": {
"detectors": [
{
"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",
"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
"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
},
"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/monty/Private/tob/tools/slither-public/scripts/../tests/expected_json/backdoor.suicidal.json exists already, the overwrite is prevented
INFO:Slither:/home/travis/build/crytic/slither/scripts/../tests/expected_json/backdoor.suicidal.json exists already, the overwrite is prevented
INFO:Slither:tests/backdoor.sol analyzed (1 contracts), 1 result(s) found

@ -1,112 +1,362 @@
[
{
"check": "constable-states",
"impact": "Informational",
"confidence": "High",
"description": "A.myFriendsAddress should be constant (tests/const_state_variables.sol#7)\nA.test should be constant (tests/const_state_variables.sol#10)\nA.text2 should be constant (tests/const_state_variables.sol#14)\nB.mySistersAddress should be constant (tests/const_state_variables.sol#26)\nMyConc.should_be_constant should be constant (tests/const_state_variables.sol#42)\nMyConc.should_be_constant_2 should be constant (tests/const_state_variables.sol#43)\n",
"elements": [
{
"success": true,
"error": null,
"results": {
"detectors": [
{
"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
}
"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
},
"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
}
}
}
}
]
},
{
"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
}
"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
},
"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
}
}
}
}
]
},
{
"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
}
"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
},
"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
}
}
}
}
]
},
{
"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
}
"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
},
"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
}
}
}
}
]
},
{
"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
}
"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
},
"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
}
}
}
}
]
},
{
"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
}
"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
},
"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
}
}
}
}
]
}
]
}
]
}

@ -6,4 +6,4 @@ B.mySistersAddress should be constant (tests/const_state_variables.sol#26)
MyConc.should_be_constant should be constant (tests/const_state_variables.sol#42)
MyConc.should_be_constant_2 should be constant (tests/const_state_variables.sol#43)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-constant
INFO:Slither:tests/const_state_variables.sol analyzed (3 contracts), 1 result(s) found
INFO:Slither:tests/const_state_variables.sol analyzed (3 contracts), 6 result(s) found

@ -1,67 +1,75 @@
[
{
"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": [
{
"success": true,
"error": null,
"results": {
"detectors": [
{
"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",
"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
"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
},
"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
}
},
{
"type": "info",
"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,252 +1,350 @@
[
{
"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": [
{
"success": true,
"error": null,
"results": {
"detectors": [
{
"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",
"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
"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
},
"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
},
"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
}
},
{
"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
}
},
{
"type": "info",
"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",
"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
"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
},
"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
},
"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
}
},
{
"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
}
},
{
"type": "info",
"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",
"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
"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
},
"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
}
},
{
"type": "info",
"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,173 +1,316 @@
[
{
"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\taddr_bad.delegatecall(data) (tests/controlled_delegatecall.sol#10)\n",
"elements": [
{
"success": true,
"error": null,
"results": {
"detectors": [
{
"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",
"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
"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)"
}
}
}
},
{
"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)"
}
}
}
]
},
{
"type": "expression",
"expression": "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
}
}
]
},
{
"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\taddr_bad.delegatecall(abi.encode(func_id,data)) (tests/controlled_delegatecall.sol#19)\n",
"elements": [
{
"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
"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
},
"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)"
}
}
}
},
{
"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)"
}
}
}
},
{
"type": "expression",
"expression": "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
}
]
}
]
}
]
}

@ -1,7 +1,7 @@
INFO:Detectors:
C.bad_delegate_call (tests/controlled_delegatecall.sol#8-11) uses delegatecall to a input-controlled function id
addr_bad.delegatecall(data) (tests/controlled_delegatecall.sol#10)
- addr_bad.delegatecall(data) (tests/controlled_delegatecall.sol#10)
C.bad_delegate_call2 (tests/controlled_delegatecall.sol#18-20) uses delegatecall to a input-controlled function id
addr_bad.delegatecall(abi.encode(func_id,data)) (tests/controlled_delegatecall.sol#19)
- addr_bad.delegatecall(abi.encode(func_id,data)) (tests/controlled_delegatecall.sol#19)
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#controlled-delegatecall
INFO:Slither:tests/controlled_delegatecall.sol analyzed (1 contracts), 2 result(s) found

@ -1,180 +1,681 @@
[
{
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#2:\n\t- Usage of \"block.blockhash()\" should be replaced with \"blockhash()\"\n",
"elements": [
{
"success": true,
"error": null,
"results": {
"detectors": [
{
"type": "variable",
"name": "globalBlockHash",
"source_mapping": {
"start": 48,
"length": 44,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
2
],
"starting_column": 5,
"ending_column": 49
}
}
]
},
{
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#7-10:\n\t- Usage of \"msg.gas\" should be replaced with \"gasleft()\"\n",
"elements": [
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#2:\n\t- Usage of \"block.blockhash()\" should be replaced with \"blockhash()\"\n",
"elements": [
{
"type": "variable",
"name": "globalBlockHash",
"source_mapping": {
"start": 48,
"length": 44,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
2
],
"starting_column": 5,
"ending_column": 49
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "ContractWithDeprecatedReferences",
"source_mapping": {
"start": 0,
"length": 906,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.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
],
"starting_column": 1,
"ending_column": null
}
}
}
}
]
},
{
"type": "expression",
"expression": "msg.gas == msg.value",
"source_mapping": {
"start": 258,
"length": 107,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
7,
8,
9,
10
],
"starting_column": 9,
"ending_column": 10
}
}
]
},
{
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#9:\n\t- Usage of \"throw\" should be replaced with \"revert()\"\n",
"elements": [
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#7-10:\n\t- Usage of \"msg.gas\" should be replaced with \"gasleft()\"\n",
"elements": [
{
"type": "node",
"name": "msg.gas == msg.value",
"source_mapping": {
"start": 258,
"length": 107,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
7,
8,
9,
10
],
"starting_column": 9,
"ending_column": 10
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "functionWithDeprecatedThrow",
"source_mapping": {
"start": 142,
"length": 229,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
5,
6,
7,
8,
9,
10,
11
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "ContractWithDeprecatedReferences",
"source_mapping": {
"start": 0,
"length": 906,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.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
],
"starting_column": 1,
"ending_column": null
}
},
"signature": "functionWithDeprecatedThrow()"
}
}
}
}
]
},
{
"type": "expression",
"expression": "None",
"source_mapping": {
"start": 349,
"length": 5,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
9
],
"starting_column": 13,
"ending_column": 18
}
}
]
},
{
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#16:\n\t- Usage of \"sha3()\" should be replaced with \"keccak256()\"\n",
"elements": [
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#9:\n\t- Usage of \"throw\" should be replaced with \"revert()\"\n",
"elements": [
{
"type": "node",
"name": "",
"source_mapping": {
"start": 349,
"length": 5,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
9
],
"starting_column": 13,
"ending_column": 18
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "functionWithDeprecatedThrow",
"source_mapping": {
"start": 142,
"length": 229,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
5,
6,
7,
8,
9,
10,
11
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "ContractWithDeprecatedReferences",
"source_mapping": {
"start": 0,
"length": 906,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.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
],
"starting_column": 1,
"ending_column": null
}
},
"signature": "functionWithDeprecatedThrow()"
}
}
}
}
]
},
{
"type": "expression",
"expression": "sha3Result = sha3()(test deprecated sha3 usage)",
"source_mapping": {
"start": 542,
"length": 55,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
16
],
"starting_column": 9,
"ending_column": 64
}
}
]
},
{
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#19:\n\t- Usage of \"block.blockhash()\" should be replaced with \"blockhash()\"\n",
"elements": [
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#16:\n\t- Usage of \"sha3()\" should be replaced with \"keccak256()\"\n",
"elements": [
{
"type": "node",
"name": "sha3Result = sha3()(test deprecated sha3 usage)",
"source_mapping": {
"start": 542,
"length": 55,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
16
],
"starting_column": 9,
"ending_column": 64
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "functionWithDeprecatedReferences",
"source_mapping": {
"start": 420,
"length": 484,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "ContractWithDeprecatedReferences",
"source_mapping": {
"start": 0,
"length": 906,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.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
],
"starting_column": 1,
"ending_column": null
}
},
"signature": "functionWithDeprecatedReferences()"
}
}
}
}
]
},
{
"type": "expression",
"expression": "blockHashResult = block.blockhash(0)",
"source_mapping": {
"start": 671,
"length": 44,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
19
],
"starting_column": 9,
"ending_column": 53
}
}
]
},
{
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#22:\n\t- Usage of \"callcode\" should be replaced with \"delegatecall\"\n",
"elements": [
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#19:\n\t- Usage of \"block.blockhash()\" should be replaced with \"blockhash()\"\n",
"elements": [
{
"type": "node",
"name": "blockHashResult = block.blockhash(0)",
"source_mapping": {
"start": 671,
"length": 44,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
19
],
"starting_column": 9,
"ending_column": 53
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "functionWithDeprecatedReferences",
"source_mapping": {
"start": 420,
"length": 484,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "ContractWithDeprecatedReferences",
"source_mapping": {
"start": 0,
"length": 906,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.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
],
"starting_column": 1,
"ending_column": null
}
},
"signature": "functionWithDeprecatedReferences()"
}
}
}
}
]
},
{
"type": "expression",
"expression": "address(this).callcode()",
"source_mapping": {
"start": 785,
"length": 24,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
22
],
"starting_column": 9,
"ending_column": 33
}
}
]
},
{
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#25:\n\t- Usage of \"suicide()\" should be replaced with \"selfdestruct()\"\n",
"elements": [
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#22:\n\t- Usage of \"callcode\" should be replaced with \"delegatecall\"\n",
"elements": [
{
"type": "node",
"name": "address(this).callcode()",
"source_mapping": {
"start": 785,
"length": 24,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
22
],
"starting_column": 9,
"ending_column": 33
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "functionWithDeprecatedReferences",
"source_mapping": {
"start": 420,
"length": 484,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "ContractWithDeprecatedReferences",
"source_mapping": {
"start": 0,
"length": 906,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.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
],
"starting_column": 1,
"ending_column": null
}
},
"signature": "functionWithDeprecatedReferences()"
}
}
}
}
]
},
{
"type": "expression",
"expression": "suicide(address)(address(0))",
"source_mapping": {
"start": 878,
"length": 19,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
25
],
"starting_column": 9,
"ending_column": 28
}
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#25:\n\t- Usage of \"suicide()\" should be replaced with \"selfdestruct()\"\n",
"elements": [
{
"type": "node",
"name": "suicide(address)(address(0))",
"source_mapping": {
"start": 878,
"length": 19,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
25
],
"starting_column": 9,
"ending_column": 28
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "functionWithDeprecatedReferences",
"source_mapping": {
"start": 420,
"length": 484,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"lines": [
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "ContractWithDeprecatedReferences",
"source_mapping": {
"start": 0,
"length": 906,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.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
],
"starting_column": 1,
"ending_column": null
}
},
"signature": "functionWithDeprecatedReferences()"
}
}
}
}
]
}
]
}
]
}

@ -1,182 +1,236 @@
[
{
"check": "erc20-indexed",
"impact": "Informational",
"confidence": "High",
"description": "IERC20Bad (tests/erc20_indexed.sol#12-21) does not mark important ERC20 parameters as 'indexed':\n\t-Transfer (tests/erc20_indexed.sol#19) does not index parameter 'from'\n\t-Transfer (tests/erc20_indexed.sol#19) does not index parameter 'to'\n\t-Approval (tests/erc20_indexed.sol#20) does not index parameter 'owner'\n\t-Approval (tests/erc20_indexed.sol#20) does not index parameter 'spender'\n",
"elements": [
{
"success": true,
"error": null,
"results": {
"detectors": [
{
"type": "function",
"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
},
"contract": {
"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
"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
},
"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"
}
}
}
]
},
{
"type": "function",
"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
},
"contract": {
"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
"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
},
"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"
}
}
}
]
},
{
"type": "function",
"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
},
"contract": {
"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
"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
},
"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"
}
}
}
]
},
{
"type": "function",
"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
},
"contract": {
"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
"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
},
"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,8 +1,7 @@
INFO:Detectors:
IERC20Bad (tests/erc20_indexed.sol#12-21) does not mark important ERC20 parameters as 'indexed':
-Transfer (tests/erc20_indexed.sol#19) does not index parameter 'from'
-Transfer (tests/erc20_indexed.sol#19) does not index parameter 'to'
-Approval (tests/erc20_indexed.sol#20) does not index parameter 'owner'
-Approval (tests/erc20_indexed.sol#20) does not index parameter 'spender'
ERC20 event IERC20Bad.Transfer (tests/erc20_indexed.sol#19) does not index parameter 'from'
ERC20 event IERC20Bad.Transfer (tests/erc20_indexed.sol#19) does not index parameter 'to'
ERC20 event IERC20Bad.Approval (tests/erc20_indexed.sol#20) does not index parameter 'owner'
ERC20 event IERC20Bad.Approval (tests/erc20_indexed.sol#20) does not index parameter 'spender'
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#unindexed-erc20-event-parameters
INFO:Slither:tests/erc20_indexed.sol analyzed (3 contracts), 1 result(s) found
INFO:Slither:tests/erc20_indexed.sol analyzed (3 contracts), 4 result(s) found

@ -1,246 +1,264 @@
[
{
"check": "external-function",
"impact": "Informational",
"confidence": "High",
"description": "ContractWithFunctionNotCalled.funcNotCalled3 (tests/external_function.sol#13-15) should be declared external\n",
"elements": [
{
"success": true,
"error": null,
"results": {
"detectors": [
{
"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",
"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
"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
},
"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",
"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
"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
},
"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",
"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
"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
},
"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",
"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
"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
},
"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