Merge pull request #613 from crytic/dev-0.7-sync-88954ac6

Synchronize 0.7
dev-0.7
Feist Josselin 4 years ago committed by GitHub
commit 8fba6ba0e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 40
      .github/workflows/ci.yml
  2. 21
      CONTRIBUTING.md
  3. 10
      Dockerfile
  4. 20
      README.md
  5. 3
      plugin_example/README.md
  6. 7
      pyproject.toml
  7. 21
      scripts/ci_generate_test_detectors_4.sh
  8. 28
      scripts/ci_generate_test_detectors_5.sh
  9. 11
      scripts/ci_generate_test_detectors_6.sh
  10. 11
      scripts/ci_generate_test_detectors_7.sh
  11. 86
      scripts/ci_test.sh
  12. 18
      scripts/ci_test_cli.sh
  13. 9
      scripts/ci_test_dapp.sh
  14. 9
      scripts/ci_test_data_dependency.sh
  15. 70
      scripts/ci_test_detectors_4.sh
  16. 51
      scripts/ci_test_detectors_5.sh
  17. 7
      scripts/ci_test_detectors_6.sh
  18. 7
      scripts/ci_test_detectors_7.sh
  19. 9
      scripts/ci_test_embark.sh
  20. 6
      scripts/ci_test_erc.sh
  21. 7
      scripts/ci_test_etherlime.sh
  22. 23
      scripts/ci_test_etherscan.sh
  23. 5
      scripts/ci_test_find_paths.sh
  24. 5
      scripts/ci_test_kspec.sh
  25. 8
      scripts/ci_test_printers.sh
  26. 2
      scripts/ci_test_prop.sh
  27. 6
      scripts/ci_test_simil.sh
  28. 9
      scripts/ci_test_slither_config.sh
  29. 7
      scripts/ci_test_truffle.sh
  30. 49
      scripts/ci_test_upgradability.sh
  31. 5
      scripts/fix_travis_relative_paths.sh
  32. 6
      scripts/json_diff.py
  33. 42
      scripts/tests_generate_expected_json_5.sh
  34. 119
      scripts/travis_test_5.sh
  35. 24
      scripts/travis_test_cli.sh
  36. 11
      scripts/travis_test_data_dependency.sh
  37. 26
      scripts/travis_test_etherscan.sh
  38. 11
      scripts/travis_test_slither_config.sh
  39. 9
      slither/__main__.py
  40. 10
      slither/core/cfg/node.py
  41. 4
      slither/core/declarations/contract.py
  42. 28
      slither/core/declarations/function.py
  43. 10
      slither/core/declarations/solidity_variables.py
  44. 29
      slither/core/expressions/binary_operation.py
  45. 8
      slither/core/expressions/call_expression.py
  46. 5
      slither/core/expressions/elementary_type_name_expression.py
  47. 75
      slither/core/slither_core.py
  48. 9
      slither/core/solidity_types/array_type.py
  49. 9
      slither/core/solidity_types/elementary_type.py
  50. 6
      slither/core/solidity_types/function_type.py
  51. 6
      slither/core/solidity_types/mapping_type.py
  52. 15
      slither/core/solidity_types/type.py
  53. 14
      slither/core/solidity_types/type_information.py
  54. 35
      slither/core/solidity_types/user_defined_type.py
  55. 2
      slither/detectors/abstract_detector.py
  56. 6
      slither/detectors/attributes/const_functions_asm.py
  57. 8
      slither/detectors/attributes/const_functions_state.py
  58. 2
      slither/detectors/attributes/constant_pragma.py
  59. 46
      slither/detectors/attributes/incorrect_solc.py
  60. 6
      slither/detectors/attributes/locked_ether.py
  61. 6
      slither/detectors/erc/incorrect_erc20_interface.py
  62. 6
      slither/detectors/erc/incorrect_erc721_interface.py
  63. 9
      slither/detectors/erc/unindexed_event_parameters.py
  64. 10
      slither/detectors/functions/arbitrary_send.py
  65. 6
      slither/detectors/functions/external_function.py
  66. 4
      slither/detectors/functions/suicidal.py
  67. 10
      slither/detectors/naming_convention/naming_convention.py
  68. 2
      slither/detectors/operations/low_level_calls.py
  69. 4
      slither/detectors/operations/unchecked_low_level_return_values.py
  70. 8
      slither/detectors/operations/unchecked_send_return_value.py
  71. 2
      slither/detectors/operations/unused_return_values.py
  72. 6
      slither/detectors/operations/void_constructor.py
  73. 4
      slither/detectors/reentrancy/reentrancy_benign.py
  74. 8
      slither/detectors/reentrancy/reentrancy_eth.py
  75. 10
      slither/detectors/reentrancy/reentrancy_events.py
  76. 8
      slither/detectors/reentrancy/reentrancy_no_gas.py
  77. 6
      slither/detectors/reentrancy/reentrancy_read_before_write.py
  78. 4
      slither/detectors/shadowing/builtin_symbols.py
  79. 6
      slither/detectors/shadowing/local.py
  80. 8
      slither/detectors/slither/name_reused.py
  81. 4
      slither/detectors/source/rtlo.py
  82. 2
      slither/detectors/statements/assembly.py
  83. 6
      slither/detectors/statements/boolean_constant_equality.py
  84. 3
      slither/detectors/statements/boolean_constant_misuse.py
  85. 4
      slither/detectors/statements/calls_in_loop.py
  86. 4
      slither/detectors/statements/controlled_delegatecall.py
  87. 4
      slither/detectors/statements/deprecated_calls.py
  88. 6
      slither/detectors/statements/divide_before_multiply.py
  89. 6
      slither/detectors/statements/incorrect_strict_equality.py
  90. 4
      slither/detectors/statements/too_many_digits.py
  91. 2
      slither/detectors/statements/tx_origin.py
  92. 6
      slither/detectors/statements/type_based_tautology.py
  93. 4
      slither/detectors/variables/possible_const_state_variables.py
  94. 2
      slither/detectors/variables/uninitialized_local_variables.py
  95. 2
      slither/detectors/variables/uninitialized_state_variables.py
  96. 6
      slither/detectors/variables/uninitialized_storage_variables.py
  97. 2
      slither/detectors/variables/unused_state_variables.py
  98. 2
      slither/printers/functions/authorization.py
  99. 2
      slither/printers/functions/cfg.py
  100. 1
      slither/printers/guidance/echidna.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,5 +1,10 @@
name: CI name: CI
defaults:
run:
# To load bashrc
shell: bash -ieo pipefail {0}
on: on:
push: push:
branches: branches:
@ -15,7 +20,23 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
type: ["4", "5", "cli", "data_dependency", "embark", "erc", "etherlime", "find_paths", "kspec", "printers", "simil", "slither_config", "truffle", "upgradability", "prop"] type: ["detectors_4",
"detectors_5",
"detectors_6",
"detectors_7",
"cli",
"data_dependency",
"embark",
"erc",
"etherlime",
"find_paths",
"kspec",
"printers",
"simil",
"slither_config",
"truffle",
"upgradability",
"prop"]
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Set up Python 3.6 - name: Set up Python 3.6
@ -25,19 +46,18 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
python setup.py install python setup.py install
# Used by travis_test.sh # Used by ci_test.sh
pip install deepdiff pip install deepdiff
sudo wget -O /usr/bin/solc-0.4.25 https://github.com/ethereum/solidity/releases/download/v0.4.25/solc-static-linux git clone https://github.com/crytic/solc-select.git
sudo chmod +x /usr/bin/solc-0.4.25 ./solc-select/scripts/install.sh
sudo wget -O /usr/bin/solc-0.5.1 https://github.com/ethereum/solidity/releases/download/v0.5.1/solc-static-linux export PATH=/home/runner/.solc-select:$PATH
sudo chmod +x /usr/bin/solc-0.5.1 echo "export PATH=/home/runner/.solc-select:$PATH" >> ~/.bashrc
sudo wget -O /usr/bin/solc-0.5.0 https://github.com/ethereum/solidity/releases/download/v0.5.0/solc-static-linux solc use 0.5.1
sudo chmod +x /usr/bin/solc-0.5.0
sudo cp /usr/bin/solc-0.5.1 /usr/bin/solc
- name: Run Tests - name: Run Tests
env: env:
TEST_TYPE: ${{ matrix.type }} TEST_TYPE: ${{ matrix.type }}
GITHUB_ETHERSCAN: ${{ secrets.GITHUB_ETHERSCAN }} GITHUB_ETHERSCAN: ${{ secrets.GITHUB_ETHERSCAN }}
run: | run: |
bash scripts/travis_test_${TEST_TYPE}.sh bash scripts/ci_test_${TEST_TYPE}.sh

@ -3,13 +3,13 @@ First, thanks for your interest in contributing to Slither! We welcome and appre
If you're unsure where to start, we recommend our [`good first issue`](https://github.com/crytic/slither/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) and [`help wanted`](https://github.com/crytic/slither/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) issue labels. If you're unsure where to start, we recommend our [`good first issue`](https://github.com/crytic/slither/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) and [`help wanted`](https://github.com/crytic/slither/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) issue labels.
# Bug reports and feature suggestions ## Bug reports and feature suggestions
Bug reports and feature suggestions can be submitted to our issue tracker. For bug reports, attaching the contract that caused the bug will help us in debugging and resolving the issue quickly. If you find a security vulnerability, do not open an issue; email opensource@trailofbits.com instead. Bug reports and feature suggestions can be submitted to our issue tracker. For bug reports, attaching the contract that caused the bug will help us in debugging and resolving the issue quickly. If you find a security vulnerability, do not open an issue; email opensource@trailofbits.com instead.
# Questions ## Questions
Questions can be submitted to the issue tracker, but you may get a faster response if you ask in our [chat room](https://empireslacking.herokuapp.com/) (in the #ethereum channel). Questions can be submitted to the issue tracker, but you may get a faster response if you ask in our [chat room](https://empireslacking.herokuapp.com/) (in the #ethereum channel).
# Code ## Code
Slither uses the pull request contribution model. Please make an account on Github, fork this repo, and submit code contributions via pull request. For more documentation, look [here](https://guides.github.com/activities/forking/). Slither uses the pull request contribution model. Please make an account on Github, fork this repo, and submit code contributions via pull request. For more documentation, look [here](https://guides.github.com/activities/forking/).
Some pull request guidelines: Some pull request guidelines:
@ -20,5 +20,18 @@ Some pull request guidelines:
- Fill out the pull request description with a summary of what your patch does, key changes that have been made, and any further points of discussion, if applicable. - Fill out the pull request description with a summary of what your patch does, key changes that have been made, and any further points of discussion, if applicable.
- Title your pull request with a brief description of what it's changing. "Fixes #123" is a good comment to add to the description, but makes for an unclear title on its own. - Title your pull request with a brief description of what it's changing. "Fixes #123" is a good comment to add to the description, but makes for an unclear title on its own.
# Development Environment ## Development Environment
Instructions for installing a development version of Slither can be found in our [wiki](https://github.com/crytic/slither/wiki/Developer-installation). Instructions for installing a development version of Slither can be found in our [wiki](https://github.com/crytic/slither/wiki/Developer-installation).
## Detectors regression tests
For each new detector, at least one regression tests must be present.
To generate the following scripts, you must have [`solc-select`](https://github.com/crytic/solc-select) installed.
- Create a test in `tests`
- Update `script/ci_test_detectors_[solc_version].sh`, and add `generate_expected_json tests/YOUR_FILENAME.sol "DETECTOR_NAME"`. Be sure that all the other lines are commented (otherwise you will regenerate the tests for all the detectores)
- Run `./script/ci_test_detectors_[solc_version].sh`. This will generate the json artifacts in `tests/expected_json`. Add the generated files to git.
- Update `scripts/ci_test_detectors_[solc_version].sh` with your new tests.
- Run `scripts/ci_test_detectors_[solc_version].sh` and check that everything worked.

@ -1,10 +1,10 @@
FROM ubuntu:bionic FROM ubuntu:bionic
LABEL name slither LABEL name=slither
LABEL src "https://github.com/trailofbits/slither" LABEL src="https://github.com/trailofbits/slither"
LABEL creator trailofbits LABEL creator=trailofbits
LABEL dockerfile_maintenance trailofbits LABEL dockerfile_maintenance=trailofbits
LABEL desc "Static Analyzer for Solidity" LABEL desc="Static Analyzer for Solidity"
RUN apt update \ RUN apt update \
&& apt upgrade -y \ && apt upgrade -y \

@ -31,13 +31,13 @@ Slither is a Solidity static analysis framework written in Python 3. It runs a s
## Bugs and Optimizations Detection ## Bugs and Optimizations Detection
Run Slither on a Truffle/Embark/Dapp/Etherlime application: Run Slither on a Truffle/Embark/Dapp/Etherlime application:
``` ```bash
slither . slither .
``` ```
Run Slither on a single file: Run Slither on a single file:
``` ```bash
$ slither tests/uninitialized.sol slither tests/uninitialized.sol
``` ```
For additional configuration, see the [usage](https://github.com/trailofbits/slither/wiki/Usage) documentation. For additional configuration, see the [usage](https://github.com/trailofbits/slither/wiki/Usage) documentation.
@ -123,7 +123,7 @@ See the [Printer documentation](https://github.com/crytic/slither/wiki/Printer-d
- `slither-check-upgradeability`: [Review `delegatecall`-based upgradeability](https://github.com/crytic/slither/wiki/Upgradeability-Checks) - `slither-check-upgradeability`: [Review `delegatecall`-based upgradeability](https://github.com/crytic/slither/wiki/Upgradeability-Checks)
- `slither-prop`: [Automatic unit tests and properties generation](https://github.com/crytic/slither/wiki/Properties-generation) - `slither-prop`: [Automatic unit tests and properties generation](https://github.com/crytic/slither/wiki/Properties-generation)
- `slither-flat`: [Flatten a codebase](https://github.com/crytic/slither/wiki/Contract-Flattening) - `slither-flat`: [Flatten a codebase](https://github.com/crytic/slither/wiki/Contract-Flattening)
- `slither-erc`: [Check the ERC's conformance](https://github.com/crytic/slither/wiki/ERC-Conformance) - `slither-check-erc`: [Check the ERC's conformance](https://github.com/crytic/slither/wiki/ERC-Conformance)
- `slither-format`: [Automatic patches generation](https://github.com/crytic/slither/wiki/Slither-format) - `slither-format`: [Automatic patches generation](https://github.com/crytic/slither/wiki/Slither-format)
See the [Tool documentation](https://github.com/crytic/slither/wiki/Tool-Documentation) for additional tools. See the [Tool documentation](https://github.com/crytic/slither/wiki/Tool-Documentation) for additional tools.
@ -136,15 +136,15 @@ Slither requires Python 3.6+ and [solc](https://github.com/ethereum/solidity/),
### Using Pip ### Using Pip
``` ```bash
$ pip3 install slither-analyzer pip3 install slither-analyzer
``` ```
### Using Git ### Using Git
```bash ```bash
$ git clone https://github.com/crytic/slither.git && cd slither git clone https://github.com/crytic/slither.git && cd slither
$ python3 setup.py install python3 setup.py install
``` ```
We recommend using an Python virtual environment, as detailed in the [Developer Installation Instructions](https://github.com/trailofbits/slither/wiki/Developer-installation), if you prefer to install Slither via git. We recommend using an Python virtual environment, as detailed in the [Developer Installation Instructions](https://github.com/trailofbits/slither/wiki/Developer-installation), if you prefer to install Slither via git.
@ -153,13 +153,13 @@ We recommend using an Python virtual environment, as detailed in the [Developer
Use the [`eth-security-toolbox`](https://github.com/trailofbits/eth-security-toolbox/) docker image. It includes all of our security tools and every major version of Solidity in a single image. `/home/share` will be mounted to `/share` in the container. Use the [`eth-security-toolbox`](https://github.com/trailofbits/eth-security-toolbox/) docker image. It includes all of our security tools and every major version of Solidity in a single image. `/home/share` will be mounted to `/share` in the container.
``` ```bash
docker pull trailofbits/eth-security-toolbox docker pull trailofbits/eth-security-toolbox
``` ```
To share a directory in the container: To share a directory in the container:
``` ```bash
docker run -it -v /home/share:/share trailofbits/eth-security-toolbox docker run -it -v /home/share:/share trailofbits/eth-security-toolbox
``` ```

@ -11,9 +11,8 @@ See the [detector documentation](https://github.com/trailofbits/slither/wiki/Add
- `slither_my_plugin/detectors/example.py`: Detector plugin skeleton. - `slither_my_plugin/detectors/example.py`: Detector plugin skeleton.
Once these files are updated with your plugin, you can install it: Once these files are updated with your plugin, you can install it:
``` ```bash
python setup.py develop python setup.py develop
``` ```
We recommend to use a Python virtual environment (for example: [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/)). We recommend to use a Python virtual environment (for example: [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/)).

@ -0,0 +1,7 @@
[tool.black]
target-version = ["py36"]
line-length = 100
[tool.pylint.messages_control]
disable = """
C0116,C0114
"""

@ -1,24 +1,10 @@
#!/usr/bin/env bash #!/usr/bin/env bash
DIR="$(cd "$(dirname "$0")" && pwd)" source "$(dirname "$0")""/ci_test.sh"
CURRENT_PATH=$(pwd)
TRAVIS_PATH='/home/travis/build/crytic/slither'
# generate_expected_json file.sol detectors solc use "0.4.25"
generate_expected_json(){
# generate output filename
# e.g. file: uninitialized.sol detector: uninitialized-state
# ---> uninitialized.uninitialized-state.json
output_filename="$DIR/../tests/expected_json/$(basename $1 .sol).$2.json"
output_filename_txt="$DIR/../tests/expected_json/$(basename $1 .sol).$2.txt"
# run slither detector on input file and save output as json # Be sure that only one of the following line is uncommented before running the script
slither "$1" --solc-disable-warnings --detect "$2" --json "$output_filename" --solc solc-0.4.25 > $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/deprecated_calls.sol "deprecated-standards" generate_expected_json tests/deprecated_calls.sol "deprecated-standards"
@ -58,3 +44,4 @@ generate_expected_json tests/deprecated_calls.sol "deprecated-standards"
#generate_expected_json tests/solc_version_incorrect.sol "solc-version" #generate_expected_json tests/solc_version_incorrect.sol "solc-version"
#generate_expected_json tests/right_to_left_override.sol "rtlo" #generate_expected_json tests/right_to_left_override.sol "rtlo"
#generate_expected_json tests/unchecked_lowlevel.sol "unchecked-lowlevel" #generate_expected_json tests/unchecked_lowlevel.sol "unchecked-lowlevel"

@ -0,0 +1,28 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.5.1"
# Be sure that only one of the following line is uncommented before running the script
# generate_expected_json tests/void-cst.sol "void-cst"
# generate_expected_json tests/solc_version_incorrect_05.ast.json "solc-version"
# generate_expected_json tests/uninitialized-0.5.1.sol "uninitialized-state"
# generate_expected_json tests/backdoor.sol "backdoor"
# generate_expected_json tests/backdoor.sol "suicidal"
# generate_expected_json tests/old_solc.sol.json "solc-version"
# generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy-eth"
# generate_expected_json tests/reentrancy-0.5.1-events.sol "reentrancy-events"
# generate_expected_json tests/tx_origin-0.5.1.sol "tx-origin"
# generate_expected_json tests/locked_ether-0.5.1.sol "locked-ether"
# generate_expected_json tests/arbitrary_send-0.5.1.sol "arbitrary-send"
# generate_expected_json tests/inline_assembly_contract-0.5.1.sol "assembly"
# generate_expected_json tests/inline_assembly_library-0.5.1.sol "assembly"
# generate_expected_json tests/constant-0.5.1.sol "constant-function-asm"
# generate_expected_json tests/constant-0.5.1.sol "constant-function-state"
# 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"

@ -0,0 +1,11 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.6.11"
# Be sure that only one of the following line is uncommented before running the script
#generate_expected_json tests/filename.sol "detector_name"

@ -0,0 +1,11 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.7.0"
# Be sure that only one of the following line is uncommented before running the script
#generate_expected_json tests/filename.sol "detector_name"

@ -0,0 +1,86 @@
#!/usr/bin/env bash
### Test Detectors
DIR="$(cd "$(dirname "$0")" && pwd)"
CURRENT_PATH=$(pwd)
TRAVIS_PATH='/home/travis/build/crytic/slither'
# test_slither file.sol detectors
test_slither(){
expected="$DIR/../tests/expected_json/$(basename "$1" .sol).$2.json"
# run slither detector on input file and save output as json
slither "$1" --solc-disable-warnings --detect "$2" --json "$DIR/tmp-test.json"
if [ $? -eq 255 ]
then
echo "Slither crashed"
exit 255
fi
if [ ! -f "$DIR/tmp-test.json" ]; then
echo ""
echo "Missing generated file"
echo ""
exit 1
fi
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$DIR/tmp-test.json" -i
result=$(python "$DIR/json_diff.py" "$expected" "$DIR/tmp-test.json")
rm "$DIR/tmp-test.json"
if [ "$result" != "{}" ]; then
echo ""
echo "failed test of file: $1, detector: $2"
echo ""
echo "$result"
echo ""
exit 1
fi
# run slither detector on input file and save output as json
slither "$1" --solc-disable-warnings --detect "$2" --legacy-ast --json "$DIR/tmp-test.json"
if [ $? -eq 255 ]
then
echo "Slither crashed"
exit 255
fi
if [ ! -f "$DIR/tmp-test.json" ]; then
echo ""
echo "Missing generated file"
echo ""
exit 1
fi
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$DIR/tmp-test.json" -i
result=$(python "$DIR/json_diff.py" "$expected" "$DIR/tmp-test.json")
rm "$DIR/tmp-test.json"
if [ "$result" != "{}" ]; then
echo ""
echo "failed test of file: $1, detector: $2"
echo ""
echo "$result"
echo ""
exit 1
fi
}
# generate_expected_json file.sol detectors
generate_expected_json(){
# generate output filename
# e.g. file: uninitialized.sol detector: uninitialized-state
# ---> uninitialized.uninitialized-state.json
output_filename="$DIR/../tests/expected_json/$(basename "$1" .sol).$2.json"
output_filename_txt="$DIR/../tests/expected_json/$(basename "$1" .sol).$2.txt"
# run slither detector on input file and save output as json
slither "$1" --solc-disable-warnings --detect "$2" --json "$output_filename" > "$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
}

@ -0,0 +1,18 @@
#!/usr/bin/env bash
### Test
if ! slither "tests/*.json" --solc-ast --ignore-return-value; then
echo "--solc-ast failed"
exit 1
fi
if ! slither "tests/*0.5*.sol" --solc-disable-warnings --ignore-return-value; then
echo "--solc-disable-warnings failed"
exit 1
fi
if ! slither "tests/*0.5*.sol" --disable-color --ignore-return-value; then
echo "--disable-color failed"
exit 1
fi

@ -3,18 +3,19 @@
### Test Dapp integration ### Test Dapp integration
mkdir test_dapp mkdir test_dapp
cd test_dapp cd test_dapp || exit 255
# The dapp init process makes a temporary local git repo and needs certain values to be set # The dapp init process makes a temporary local git repo and needs certain values to be set
git config --global user.email "ci@trailofbits.com" git config --global user.email "ci@trailofbits.com"
git config --global user.name "CI User" git config --global user.name "CI User"
curl https://nixos.org/nix/install | sh curl https://nixos.org/nix/install | sh
# shellcheck disable=SC1090
. "$HOME/.nix-profile/etc/profile.d/nix.sh" . "$HOME/.nix-profile/etc/profile.d/nix.sh"
nix-env -iA nixpkgs.cachix nix-env -iA nixpkgs.cachix
cachix use dapp cachix use dapp
git clone --recursive https://github.com/dapphub/dapptools $HOME/.dapp/dapptools git clone --recursive https://github.com/dapphub/dapptools "$HOME/.dapp/dapptools"
nix-env -f $HOME/.dapp/dapptools -iA dapp seth solc hevm ethsign nix-env -f "$HOME/.dapp/dapptools" -iA dapp seth solc hevm ethsign
dapp init dapp init
@ -26,4 +27,4 @@ then
fi fi
echo "Truffle test failed" echo "Truffle test failed"
exit -1 exit 255

@ -0,0 +1,9 @@
#!/usr/bin/env bash
### Test data dependecy
if ! python ./examples/scripts/data_dependency.py ./examples/scripts/data_dependency.sol; then
echo "data dependency failed"
exit 1
fi
exit 0

@ -1,73 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
### Test Detectors source "$(dirname "$0")""/ci_test.sh"
DIR="$(cd "$(dirname "$0")" && pwd)"
CURRENT_PATH=$(pwd)
TRAVIS_PATH='/home/travis/build/crytic/slither'
# test_slither file.sol detectors
test_slither(){
expected="$DIR/../tests/expected_json/$(basename $1 .sol).$2.json"
# run slither detector on input file and save output as json
slither "$1" --solc-disable-warnings --detect "$2" --json "$DIR/tmp-test.json" --solc solc-0.4.25
if [ $? -eq 255 ]
then
echo "Slither crashed"
exit -1
fi
if [ ! -f "$DIR/tmp-test.json" ]; then
echo ""
echo "Missing generated file"
echo ""
exit 1
fi
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$DIR/tmp-test.json" -i
result=$(python "$DIR/json_diff.py" "$expected" "$DIR/tmp-test.json")
rm "$DIR/tmp-test.json"
if [ "$result" != "{}" ]; then
echo ""
echo "failed test of file: $1, detector: $2"
echo ""
echo "$result"
echo ""
exit 1
fi
# run slither detector on input file and save output as json
slither "$1" --solc-disable-warnings --detect "$2" --legacy-ast --json "$DIR/tmp-test.json" --solc solc-0.4.25
if [ $? -eq 255 ]
then
echo "Slither crashed"
exit -1
fi
if [ ! -f "$DIR/tmp-test.json" ]; then
echo ""
echo "Missing generated file"
echo ""
exit 1
fi
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$DIR/tmp-test.json" -i
result=$(python "$DIR/json_diff.py" "$expected" "$DIR/tmp-test.json")
rm "$DIR/tmp-test.json"
if [ "$result" != "{}" ]; then
echo ""
echo "failed test of file: $1, detector: $2"
echo ""
echo "$result"
echo ""
exit 1
fi
}
solc use "0.4.25"
test_slither tests/unchecked_lowlevel.sol "unchecked-lowlevel" test_slither tests/unchecked_lowlevel.sol "unchecked-lowlevel"
test_slither tests/deprecated_calls.sol "deprecated-standards" test_slither tests/deprecated_calls.sol "deprecated-standards"
@ -92,7 +27,6 @@ test_slither tests/const_state_variables.sol "constable-states"
test_slither tests/external_function.sol "external-function" test_slither tests/external_function.sol "external-function"
test_slither tests/external_function_2.sol "external-function" test_slither tests/external_function_2.sol "external-function"
test_slither tests/naming_convention.sol "naming-convention" test_slither tests/naming_convention.sol "naming-convention"
#test_slither tests/complex_func.sol "complex-function"
test_slither tests/controlled_delegatecall.sol "controlled-delegatecall" test_slither tests/controlled_delegatecall.sol "controlled-delegatecall"
test_slither tests/uninitialized_local_variable.sol "uninitialized-local" test_slither tests/uninitialized_local_variable.sol "uninitialized-local"
test_slither tests/constant.sol "constant-function-asm" test_slither tests/constant.sol "constant-function-asm"

@ -0,0 +1,51 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.5.1"
test_slither tests/void-cst.sol "void-cst"
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"
test_slither tests/old_solc.sol.json "solc-version"
test_slither tests/reentrancy-0.5.1.sol "reentrancy-eth"
test_slither tests/reentrancy-0.5.1-events.sol "reentrancy-events"
test_slither tests/tx_origin-0.5.1.sol "tx-origin"
test_slither tests/unused_state.sol "unused-state"
test_slither tests/locked_ether-0.5.1.sol "locked-ether"
test_slither tests/arbitrary_send-0.5.1.sol "arbitrary-send"
test_slither tests/inline_assembly_contract-0.5.1.sol "assembly"
test_slither tests/inline_assembly_library-0.5.1.sol "assembly"
test_slither tests/low_level_calls.sol "low-level-calls"
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/controlled_delegatecall.sol "controlled-delegatecall"
test_slither tests/constant-0.5.1.sol "constant-function-asm"
test_slither tests/constant-0.5.1.sol "constant-function-state"
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
if ! python examples/scripts/functions_called.py examples/scripts/functions_called.sol; then
exit 1
fi
if ! python examples/scripts/functions_writing.py examples/scripts/functions_writing.sol; then
exit 1
fi
if ! python examples/scripts/variable_in_condition.py examples/scripts/variable_in_condition.sol; then
exit 1
fi
exit 0

@ -0,0 +1,7 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.6.11"
# test_slither tests/filename.sol "detector_name"

@ -0,0 +1,7 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.7.0"
# test_slither tests/filename.sol "detector_name"

@ -3,24 +3,25 @@
### Test embark integration ### Test embark integration
mkdir test_embark mkdir test_embark
cd test_embark cd test_embark || exit 255
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
# shellcheck disable=SC1090
source ~/.nvm/nvm.sh source ~/.nvm/nvm.sh
nvm install 10.17.0 nvm install 10.17.0
nvm use 10.17.0 nvm use 10.17.0
npm install -g embark@4.2.0 npm install -g embark@4.2.0
embark demo embark demo
cd embark_demo cd embark_demo || exit 255
npm install npm install
slither . --embark-overwrite-config slither . --embark-overwrite-config
if [ $? -eq 3 ] if [ $? -eq 4 ]
then then
exit 0 exit 0
fi fi
echo "Embark test failed" echo "Embark test failed"
exit -1 exit 255

@ -4,7 +4,8 @@
DIR_TESTS="tests/check-erc" DIR_TESTS="tests/check-erc"
slither-check-erc "$DIR_TESTS/erc20.sol" ERC20 --solc solc-0.5.0 > test_1.txt 2>&1 solc use 0.5.0
slither-check-erc "$DIR_TESTS/erc20.sol" ERC20 > test_1.txt 2>&1
DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt") DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -12,9 +13,8 @@ then
cat test_1.txt cat test_1.txt
echo "" echo ""
cat "$DIR_TESTS/test_1.txt" cat "$DIR_TESTS/test_1.txt"
exit -1 exit 255
fi fi
rm test_1.txt rm test_1.txt

@ -3,9 +3,10 @@
### Test etherlime integration ### Test etherlime integration
mkdir test_etherlime mkdir test_etherlime
cd test_etherlime cd test_etherlime || exit 255
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
# shellcheck disable=SC1090
source ~/.nvm/nvm.sh source ~/.nvm/nvm.sh
nvm install 10.17.0 nvm install 10.17.0
nvm use 10.17.0 nvm use 10.17.0
@ -14,10 +15,10 @@ npm i -g etherlime
etherlime init etherlime init
slither . slither .
if [ $? -eq 6 ] if [ $? -eq 7 ]
then then
exit 0 exit 0
fi fi
echo "Etherlime test failed" echo "Etherlime test failed"
exit -1 exit 255

@ -0,0 +1,23 @@
#!/usr/bin/env bash
### Test etherscan integration
mkdir etherscan
cd etherscan || exit 255
slither 0x7F37f78cBD74481E593F9C737776F7113d76B315 --etherscan-apikey "$GITHUB_ETHERSCAN"
if [ $? -ne 5 ]
then
echo "Etherscan test failed"
exit 255
fi
slither rinkeby:0xFe05820C5A92D9bc906D4A46F662dbeba794d3b7 --etherscan-apikey "$GITHUB_ETHERSCAN"
if [ $? -ne 70 ]
then
echo "Etherscan test failed"
exit 255
fi

@ -4,13 +4,14 @@
DIR_TESTS="tests/possible_paths" DIR_TESTS="tests/possible_paths"
slither-find-paths "$DIR_TESTS/paths.sol" A.destination --solc solc-0.5.0 > test_possible_paths.txt 2>&1 solc use "0.5.0"
slither-find-paths "$DIR_TESTS/paths.sol" A.destination > test_possible_paths.txt 2>&1
DIFF=$(diff test_possible_paths.txt "$DIR_TESTS/paths.txt") DIFF=$(diff test_possible_paths.txt "$DIR_TESTS/paths.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
echo "slither-find-paths failed" echo "slither-find-paths failed"
cat test_possible_paths.txt cat test_possible_paths.txt
cat "$DIR_TESTS/paths.txt" cat "$DIR_TESTS/paths.txt"
exit -1 exit 255
fi fi
rm test_possible_paths.txt rm test_possible_paths.txt

@ -2,7 +2,8 @@
DIR_TESTS="tests/check-kspec" DIR_TESTS="tests/check-kspec"
slither-check-kspec "$DIR_TESTS/safeAdd/safeAdd.sol" "$DIR_TESTS/safeAdd/spec.md" --solc solc-0.5.0 > test_1.txt 2>&1 solc use "0.5.0"
slither-check-kspec "$DIR_TESTS/safeAdd/safeAdd.sol" "$DIR_TESTS/safeAdd/spec.md" > test_1.txt 2>&1
DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt") DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -10,7 +11,7 @@ then
cat test_1.txt cat test_1.txt
echo "" echo ""
cat "$DIR_TESTS/test_1.txt" cat "$DIR_TESTS/test_1.txt"
exit -1 exit 255
fi fi
rm test_1.txt rm test_1.txt

@ -5,11 +5,11 @@
# Needed for evm printer # Needed for evm printer
pip install evm-cfg-builder pip install evm-cfg-builder
slither "tests/*.json" --print all --json - if ! slither "tests/*.json" --print all --json -; then
if [ $? -ne 0 ]; then
echo "Printer tests failed" echo "Printer tests failed"
exit 1 exit 1
fi fi
slither examples/scripts/test_evm_api.sol --print evm --solc solc-0.5.1 solc use "0.5.1"
slither examples/scripts/test_evm_api.sol --print evm

@ -2,7 +2,7 @@
### Test slither-prop ### Test slither-prop
cd examples/slither-prop cd examples/slither-prop || exit 1
slither-prop . --contract ERC20Buggy slither-prop . --contract ERC20Buggy
if [ ! -f contracts/crytic/TestERC20BuggyTransferable.sol ]; then if [ ! -f contracts/crytic/TestERC20BuggyTransferable.sol ]; then
echo "slither-prop failed" echo "slither-prop failed"

@ -7,15 +7,17 @@ pip3.6 install https://github.com/facebookresearch/fastText/archive/0.2.0.zip
### Test slither-simil ### Test slither-simil
solc use "0.4.25"
DIR_TESTS="tests/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 slither-simil info "" --filename $DIR_TESTS/../complex_func.sol --fname Complex.complexExternalWrites > test_1.txt 2>&1
DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt") DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
echo "slither-simil failed" echo "slither-simil failed"
cat test_1.txt cat test_1.txt
cat "$DIR_TESTS/test_1.txt" cat "$DIR_TESTS/test_1.txt"
exit -1 exit 255
fi fi
rm test_1.txt rm test_1.txt

@ -0,0 +1,9 @@
#!/usr/bin/env bash
### Test
if ! slither "tests/*.json" --config "tests/config/slither.config.json"; then
echo "Config failed"
exit 1
fi

@ -3,9 +3,10 @@
### Test truffle integration ### Test truffle integration
mkdir test_truffle mkdir test_truffle
cd test_truffle cd test_truffle || exit 255
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
# shellcheck disable=SC1090
source ~/.nvm/nvm.sh source ~/.nvm/nvm.sh
nvm install --lts nvm install --lts
nvm use --lts nvm use --lts
@ -14,10 +15,10 @@ npm install -g truffle
truffle unbox metacoin truffle unbox metacoin
slither . slither .
if [ $? -eq 5 ] if [ $? -eq 8 ]
then then
exit 0 exit 0
fi fi
echo "Truffle test failed" echo "Truffle test failed"
exit -1 exit 255

@ -3,8 +3,9 @@
### Test slither-check-upgradeability ### Test slither-check-upgradeability
DIR_TESTS="tests/check-upgradeability" DIR_TESTS="tests/check-upgradeability"
solc use "0.5.0"
slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --solc solc-0.5.0 > test_1.txt 2>&1 slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy > test_1.txt 2>&1
DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt") DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -12,10 +13,10 @@ then
cat test_1.txt cat test_1.txt
echo "" echo ""
cat "$DIR_TESTS/test_1.txt" cat "$DIR_TESTS/test_1.txt"
exit -1 exit 255
fi fi
slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --solc solc-0.5.0 --new-contract-filename "$DIR_TESTS/contractV2.sol" --new-contract-name ContractV2 > test_2.txt 2>&1 slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --new-contract-filename "$DIR_TESTS/contractV2.sol" --new-contract-name ContractV2 > test_2.txt 2>&1
DIFF=$(diff test_2.txt "$DIR_TESTS/test_2.txt") DIFF=$(diff test_2.txt "$DIR_TESTS/test_2.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -23,10 +24,10 @@ then
cat test_2.txt cat test_2.txt
echo "" echo ""
cat "$DIR_TESTS/test_2.txt" cat "$DIR_TESTS/test_2.txt"
exit -1 exit 255
fi fi
slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --solc solc-0.5.0 --new-contract-filename "$DIR_TESTS/contractV2_bug.sol" --new-contract-name ContractV2 > test_3.txt 2>&1 slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --new-contract-filename "$DIR_TESTS/contractV2_bug.sol" --new-contract-name ContractV2 > test_3.txt 2>&1
DIFF=$(diff test_3.txt "$DIR_TESTS/test_3.txt") DIFF=$(diff test_3.txt "$DIR_TESTS/test_3.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -34,10 +35,10 @@ then
cat test_3.txt cat test_3.txt
echo "" echo ""
cat "$DIR_TESTS/test_3.txt" cat "$DIR_TESTS/test_3.txt"
exit -1 exit 255
fi fi
slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --solc solc-0.5.0 --new-contract-filename "$DIR_TESTS/contractV2_bug2.sol" --new-contract-name ContractV2 > test_4.txt 2>&1 slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --new-contract-filename "$DIR_TESTS/contractV2_bug2.sol" --new-contract-name ContractV2 > test_4.txt 2>&1
DIFF=$(diff test_4.txt "$DIR_TESTS/test_4.txt") DIFF=$(diff test_4.txt "$DIR_TESTS/test_4.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -45,10 +46,10 @@ then
cat test_4.txt cat test_4.txt
echo "" echo ""
cat "$DIR_TESTS/test_4.txt" cat "$DIR_TESTS/test_4.txt"
exit -1 exit 255
fi fi
slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_no_bug --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --solc solc-0.5.0 > test_5.txt 2>&1 slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_no_bug --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy > test_5.txt 2>&1
DIFF=$(diff test_5.txt "$DIR_TESTS/test_5.txt") DIFF=$(diff test_5.txt "$DIR_TESTS/test_5.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -58,10 +59,10 @@ then
cat "$DIR_TESTS/test_5.txt" cat "$DIR_TESTS/test_5.txt"
echo "" echo ""
echo "$DIFF" echo "$DIFF"
exit -1 exit 255
fi fi
slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_no_bug --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --solc solc-0.5.0 > test_5.txt 2>&1 slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_no_bug --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy > test_5.txt 2>&1
DIFF=$(diff test_5.txt "$DIR_TESTS/test_5.txt") DIFF=$(diff test_5.txt "$DIR_TESTS/test_5.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -71,11 +72,11 @@ then
cat "$DIR_TESTS/test_5.txt" cat "$DIR_TESTS/test_5.txt"
echo "" echo ""
echo "$DIFF" echo "$DIFF"
exit -1 exit 255
fi fi
slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_lack_to_call_modifier --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --solc solc-0.5.0 > test_6.txt 2>&1 slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_lack_to_call_modifier --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy > test_6.txt 2>&1
DIFF=$(diff test_6.txt "$DIR_TESTS/test_6.txt") DIFF=$(diff test_6.txt "$DIR_TESTS/test_6.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -85,11 +86,11 @@ then
cat "$DIR_TESTS/test_6.txt" cat "$DIR_TESTS/test_6.txt"
echo "" echo ""
echo "$DIFF" echo "$DIFF"
exit -1 exit 255
fi fi
slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_not_called_super_init --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --solc solc-0.5.0 > test_7.txt 2>&1 slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_not_called_super_init --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy > test_7.txt 2>&1
DIFF=$(diff test_7.txt "$DIR_TESTS/test_7.txt") DIFF=$(diff test_7.txt "$DIR_TESTS/test_7.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -99,10 +100,10 @@ then
cat "$DIR_TESTS/test_7.txt" cat "$DIR_TESTS/test_7.txt"
echo "" echo ""
echo "$DIFF" echo "$DIFF"
exit -1 exit 255
fi fi
slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_no_bug_inherits --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --solc solc-0.5.0 > test_8.txt 2>&1 slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_no_bug_inherits --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy > test_8.txt 2>&1
DIFF=$(diff test_8.txt "$DIR_TESTS/test_8.txt") DIFF=$(diff test_8.txt "$DIR_TESTS/test_8.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -112,10 +113,10 @@ then
cat "$DIR_TESTS/test_8.txt" cat "$DIR_TESTS/test_8.txt"
echo "" echo ""
echo "$DIFF" echo "$DIFF"
exit -1 exit 255
fi fi
slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_double_call --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy --solc solc-0.5.0 > test_9.txt 2>&1 slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_double_call --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy > test_9.txt 2>&1
DIFF=$(diff test_9.txt "$DIR_TESTS/test_9.txt") DIFF=$(diff test_9.txt "$DIR_TESTS/test_9.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -125,10 +126,10 @@ then
cat "$DIR_TESTS/test_9.txt" cat "$DIR_TESTS/test_9.txt"
echo "" echo ""
echo "$DIFF" echo "$DIFF"
exit -1 exit 255
fi fi
slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --solc solc-0.5.0 --new-contract-filename "$DIR_TESTS/contract_v2_constant.sol" --new-contract-name ContractV2 > test_10.txt 2>&1 slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --new-contract-filename "$DIR_TESTS/contract_v2_constant.sol" --new-contract-name ContractV2 > test_10.txt 2>&1
DIFF=$(diff test_10.txt "$DIR_TESTS/test_10.txt") DIFF=$(diff test_10.txt "$DIR_TESTS/test_10.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -138,10 +139,10 @@ then
cat "$DIR_TESTS/test_10.txt" cat "$DIR_TESTS/test_10.txt"
echo "" echo ""
echo "$DIFF" echo "$DIFF"
exit -1 exit 255
fi fi
slither-check-upgradeability "$DIR_TESTS/contract_v1_var_init.sol" ContractV1 --solc solc-0.5.0 > test_11.txt 2>&1 slither-check-upgradeability "$DIR_TESTS/contract_v1_var_init.sol" ContractV1 > test_11.txt 2>&1
DIFF=$(diff test_11.txt "$DIR_TESTS/test_11.txt") DIFF=$(diff test_11.txt "$DIR_TESTS/test_11.txt")
if [ "$DIFF" != "" ] if [ "$DIFF" != "" ]
then then
@ -151,7 +152,7 @@ then
cat "$DIR_TESTS/test_11.txt" cat "$DIR_TESTS/test_11.txt"
echo "" echo ""
echo "$DIFF" echo "$DIFF"
exit -1 exit 255
fi fi
rm test_1.txt rm test_1.txt

@ -1,5 +0,0 @@
CURRENT_PATH=$(pwd)
TRAVIS_PATH='/home/travis/build/crytic/slither'
for f in tests/expected_json/*json; do
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$f" -i
done

@ -22,6 +22,7 @@ for elem in d2:
if "description" in elem: if "description" in elem:
del elem["description"] del elem["description"]
def removes_lines(d): def removes_lines(d):
if isinstance(d, list): if isinstance(d, list):
for sub in d: for sub in d:
@ -29,11 +30,12 @@ def removes_lines(d):
return return
if not isinstance(d, dict): if not isinstance(d, dict):
return return
if 'lines' in d: if "lines" in d:
del d['lines'] del d["lines"]
for key in d.keys(): for key in d.keys():
removes_lines(d[key]) removes_lines(d[key])
results = DeepDiff(d1, d2, ignore_order=True, verbose_level=2) results = DeepDiff(d1, d2, ignore_order=True, verbose_level=2)
removes_lines(results) removes_lines(results)
pprint(results) pprint(results)

@ -1,42 +0,0 @@
#!/usr/bin/env bash
DIR="$(cd "$(dirname "$0")" && pwd)"
CURRENT_PATH=$(pwd)
TRAVIS_PATH='/home/travis/build/crytic/slither'
# generate_expected_json file.sol detectors
generate_expected_json(){
# generate output filename
# e.g. file: uninitialized.sol detector: uninitialized-state
# ---> uninitialized.uninitialized-state.json
output_filename="$DIR/../tests/expected_json/$(basename $1 .sol).$2.json"
output_filename_txt="$DIR/../tests/expected_json/$(basename $1 .sol).$2.txt"
# run slither detector on input file and save output as 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/void-cst.sol "void-cst"
generate_expected_json tests/solc_version_incorrect_05.ast.json "solc-version"
generate_expected_json tests/uninitialized-0.5.1.sol "uninitialized-state"
generate_expected_json tests/backdoor.sol "backdoor"
generate_expected_json tests/backdoor.sol "suicidal"
generate_expected_json tests/old_solc.sol.json "solc-version"
generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy-eth"
generate_expected_json tests/reentrancy-0.5.1-events.sol "reentrancy-events"
generate_expected_json tests/tx_origin-0.5.1.sol "tx-origin"
generate_expected_json tests/locked_ether-0.5.1.sol "locked-ether"
generate_expected_json tests/arbitrary_send-0.5.1.sol "arbitrary-send"
generate_expected_json tests/inline_assembly_contract-0.5.1.sol "assembly"
generate_expected_json tests/inline_assembly_library-0.5.1.sol "assembly"
generate_expected_json tests/constant-0.5.1.sol "constant-function-asm"
generate_expected_json tests/constant-0.5.1.sol "constant-function-state"
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,119 +0,0 @@
#!/usr/bin/env bash
### Test Detectors
DIR="$(cd "$(dirname "$0")" && pwd)"
CURRENT_PATH=$(pwd)
TRAVIS_PATH='/home/travis/build/crytic/slither'
# test_slither file.sol detectors
test_slither(){
expected="$DIR/../tests/expected_json/$(basename $1 .sol).$2.json"
# run slither detector on input file and save output as json
slither "$1" --solc-disable-warnings --detect "$2" --json "$DIR/tmp-test.json" --solc solc-0.5.1
if [ $? -eq 255 ]
then
echo "Slither crashed"
exit -1
fi
if [ ! -f "$DIR/tmp-test.json" ]; then
echo ""
echo "Missing generated file"
echo ""
exit 1
fi
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$DIR/tmp-test.json" -i
result=$(python "$DIR/json_diff.py" "$expected" "$DIR/tmp-test.json")
rm "$DIR/tmp-test.json"
if [ "$result" != "{}" ]; then
echo ""
echo "failed test of file: $1, detector: $2"
echo ""
echo "$result"
echo ""
exit 1
fi
# run slither detector on input file and save output as json
slither "$1" --solc-disable-warnings --detect "$2" --legacy-ast --json "$DIR/tmp-test.json" --solc solc-0.5.1
if [ $? -eq 255 ]
then
echo "Slither crashed"
exit -1
fi
if [ ! -f "$DIR/tmp-test.json" ]; then
echo ""
echo "Missing generated file"
echo ""
exit 1
fi
sed "s|$CURRENT_PATH|$TRAVIS_PATH|g" "$DIR/tmp-test.json" -i
result=$(python "$DIR/json_diff.py" "$expected" "$DIR/tmp-test.json")
rm "$DIR/tmp-test.json"
if [ "$result" != "{}" ]; then
echo ""
echo "failed test of file: $1, detector: $2"
echo ""
echo "$result"
echo ""
exit 1
fi
}
test_slither tests/void-cst.sol "void-cst"
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"
test_slither tests/old_solc.sol.json "solc-version"
test_slither tests/reentrancy-0.5.1.sol "reentrancy-eth"
test_slither tests/reentrancy-0.5.1-events.sol "reentrancy-events"
test_slither tests/tx_origin-0.5.1.sol "tx-origin"
test_slither tests/unused_state.sol "unused-state"
test_slither tests/locked_ether-0.5.1.sol "locked-ether"
test_slither tests/arbitrary_send-0.5.1.sol "arbitrary-send"
test_slither tests/inline_assembly_contract-0.5.1.sol "assembly"
test_slither tests/inline_assembly_library-0.5.1.sol "assembly"
test_slither tests/low_level_calls.sol "low-level-calls"
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/controlled_delegatecall.sol "controlled-delegatecall"
test_slither tests/constant-0.5.1.sol "constant-function-asm"
test_slither tests/constant-0.5.1.sol "constant-function-state"
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
python examples/scripts/functions_called.py examples/scripts/functions_called.sol
if [ $? -ne 0 ]; then
exit 1
fi
python examples/scripts/functions_writing.py examples/scripts/functions_writing.sol
if [ $? -ne 0 ]; then
exit 1
fi
python examples/scripts/variable_in_condition.py examples/scripts/variable_in_condition.sol
if [ $? -ne 0 ]; then
exit 1
fi
exit 0

@ -1,24 +0,0 @@
#!/usr/bin/env bash
### Test
slither "tests/*.json" --solc-ast --ignore-return-value
if [ $? -ne 0 ]; then
echo "--solc-ast failed"
exit 1
fi
slither "tests/*0.5*.sol" --solc-disable-warnings --ignore-return-value
if [ $? -ne 0 ]; then
echo "--solc-disable-warnings failed"
exit 1
fi
slither "tests/*0.5*.sol" --disable-color --ignore-return-value
if [ $? -ne 0 ]; then
echo "--disable-color failed"
exit 1
fi

@ -1,11 +0,0 @@
#!/usr/bin/env bash
### Test data dependecy
python ./examples/scripts/data_dependency.py ./examples/scripts/data_dependency.sol
if [ $? -ne 0 ]; then
echo "data dependency failed"
exit 1
fi
exit 0

@ -1,26 +0,0 @@
#!/usr/bin/env bash
### Test etherscan integration
mkdir etherscan
cd etherscan
wget -O solc-0.4.25 https://github.com/ethereum/solidity/releases/download/v0.4.25/solc-static-linux
chmod +x solc-0.4.25
slither 0x7F37f78cBD74481E593F9C737776F7113d76B315 --solc "./solc-0.4.25" --etherscan-apikey $GITHUB_ETHERSCAN
if [ $? -ne 5 ]
then
echo "Etherscan test failed"
exit -1
fi
slither rinkeby:0xFe05820C5A92D9bc906D4A46F662dbeba794d3b7 --solc "./solc-0.4.25" --etherscan-apikey $GITHUB_ETHERSCAN
if [ $? -ne 70 ]
then
echo "Etherscan test failed"
exit -1
fi

@ -1,11 +0,0 @@
#!/usr/bin/env bash
### Test
slither "tests/*.json" --config "tests/config/slither.config.json"
if [ $? -ne 0 ]; then
echo "Config failed"
exit 1
fi

@ -473,6 +473,11 @@ def parse_args(detector_classes, printer_classes):
# if the json is splitted in different files # if the json is splitted in different files
parser.add_argument("--splitted", help=argparse.SUPPRESS, action="store_true", default=False) parser.add_argument("--splitted", help=argparse.SUPPRESS, action="store_true", default=False)
# Disable the throw/catch on partial analyses
parser.add_argument(
"--disallow-partial", help=argparse.SUPPRESS, action="store_true", default=False
)
if len(sys.argv) == 1: if len(sys.argv) == 1:
parser.print_help(sys.stderr) parser.print_help(sys.stderr)
sys.exit(1) sys.exit(1)
@ -556,6 +561,9 @@ class FormatterCryticCompile(logging.Formatter):
def main(): def main():
# Codebase with complex domninators can lead to a lot of SSA recursive call
sys.setrecursionlimit(1500)
detectors, printers = get_detectors_and_printers() detectors, printers = get_detectors_and_printers()
main_impl(all_detector_classes=detectors, all_printer_classes=printers) main_impl(all_detector_classes=detectors, all_printer_classes=printers)
@ -733,7 +741,6 @@ def main_impl(all_detector_classes, all_printer_classes):
logging.error("Error in %s" % args.filename) logging.error("Error in %s" % args.filename)
logging.error(output_error) logging.error(output_error)
# If we are outputting JSON, capture the redirected output and disable the redirect to output the final JSON. # If we are outputting JSON, capture the redirected output and disable the redirect to output the final JSON.
if outputting_json: if outputting_json:
if "console" in args.json_types: if "console" in args.json_types:

@ -651,13 +651,13 @@ class Node(SourceMapping, ChildFunction):
@property @property
def son_true(self) -> Optional["Node"]: def son_true(self) -> Optional["Node"]:
if self.type == NodeType.IF: if self.type in [NodeType.IF, NodeType.IFLOOP]:
return self._sons[0] return self._sons[0]
return None return None
@property @property
def son_false(self) -> Optional["Node"]: def son_false(self) -> Optional["Node"]:
if self.type == NodeType.IF and len(self._sons) >= 1: if self.type in [NodeType.IF, NodeType.IFLOOP] and len(self._sons) >= 1:
return self._sons[1] return self._sons[1]
return None return None
@ -984,11 +984,11 @@ class Node(SourceMapping, ChildFunction):
################################################################################### ###################################################################################
def __str__(self): def __str__(self):
additional_info = '' additional_info = ""
if self.expression: if self.expression:
additional_info += ' ' + str(self.expression) additional_info += " " + str(self.expression)
elif self.variable_declaration: elif self.variable_declaration:
additional_info += ' ' + str(self.variable_declaration) additional_info += " " + str(self.variable_declaration)
txt = str(self._node_type) + additional_info txt = str(self._node_type) + additional_info
return txt return txt

@ -54,7 +54,7 @@ class Contract(ChildSlither, SourceMapping):
self._structures: Dict[str, "Structure"] = {} self._structures: Dict[str, "Structure"] = {}
self._events: Dict[str, "Event"] = {} self._events: Dict[str, "Event"] = {}
self._variables: Dict[str, "StateVariable"] = {} self._variables: Dict[str, "StateVariable"] = {}
self._variables_ordered: List["StateVariable"] = [] # contain also shadowed variables self._variables_ordered: List["StateVariable"] = []
self._modifiers: Dict[str, "Modifier"] = {} self._modifiers: Dict[str, "Modifier"] = {}
self._functions: Dict[str, "Function"] = {} self._functions: Dict[str, "Function"] = {}
self._linearizedBaseContracts = List[int] self._linearizedBaseContracts = List[int]
@ -255,7 +255,7 @@ class Contract(ChildSlither, SourceMapping):
@property @property
def state_variables_ordered(self) -> List["StateVariable"]: def state_variables_ordered(self) -> List["StateVariable"]:
""" """
list(StateVariable): List of the state variables by order of declaration. Contains also shadowed variables list(StateVariable): List of the state variables by order of declaration.
""" """
return list(self._variables_ordered) return list(self._variables_ordered)

@ -89,6 +89,7 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
def __init__(self): def __init__(self):
super(Function, self).__init__() super(Function, self).__init__()
self._scope: List[str] = []
self._name: Optional[str] = None self._name: Optional[str] = None
self._view: bool = False self._view: bool = False
self._pure: bool = False self._pure: bool = False
@ -200,6 +201,20 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
def name(self, new_name: str): def name(self, new_name: str):
self._name = new_name self._name = new_name
@property
def scope(self) -> List[str]:
"""
Return a list of name representing the scope of the function
This is used to model nested functions declared in YUL
:return:
"""
return self._scope
@scope.setter
def scope(self, new_scope: List[str]):
self._scope = new_scope
@property @property
def full_name(self) -> str: def full_name(self) -> str:
""" """
@ -207,7 +222,7 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
Return the function signature without the return values Return the function signature without the return values
""" """
name, parameters, _ = self.signature name, parameters, _ = self.signature
return name + "(" + ",".join(parameters) + ")" return ".".join(self._scope + [name]) + "(" + ",".join(parameters) + ")"
@property @property
def canonical_name(self) -> str: def canonical_name(self) -> str:
@ -216,7 +231,12 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
Return the function signature without the return values Return the function signature without the return values
""" """
name, parameters, _ = self.signature name, parameters, _ = self.signature
return self.contract_declarer.name + "." + name + "(" + ",".join(parameters) + ")" return (
".".join([self.contract_declarer.name] + self._scope + [name])
+ "("
+ ",".join(parameters)
+ ")"
)
@property @property
def contains_assembly(self) -> bool: def contains_assembly(self) -> bool:
@ -1282,7 +1302,7 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
if node.irs: if node.irs:
label += "\nIRs:\n" + "\n".join([str(ir) for ir in node.irs]) label += "\nIRs:\n" + "\n".join([str(ir) for ir in node.irs])
content += '{}[label="{}"];\n'.format(node.node_id, label) content += '{}[label="{}"];\n'.format(node.node_id, label)
if node.type == NodeType.IF: if node.type in [NodeType.IF, NodeType.IFLOOP]:
true_node = node.son_true true_node = node.son_true
if true_node: if true_node:
content += '{}->{}[label="True"];\n'.format(node.node_id, true_node.node_id) content += '{}->{}[label="True"];\n'.format(node.node_id, true_node.node_id)
@ -1538,7 +1558,7 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
if self._entry_point is None: if self._entry_point is None:
return dict() return dict()
# node, values # node, values
to_explore: List[Tuple[Node, Dict]] = [(self._entry_point, dict())] to_explore: List[Tuple["Node", Dict]] = [(self._entry_point, dict())]
# node -> values # node -> values
explored: Dict = dict() explored: Dict = dict()
# name -> instances # name -> instances

@ -66,6 +66,7 @@ SOLIDITY_FUNCTIONS: Dict[str, List[str]] = {
# abi.decode returns an a list arbitrary types # abi.decode returns an a list arbitrary types
"abi.decode()": [], "abi.decode()": [],
"type(address)": [], "type(address)": [],
"type()": [], # 0.6.8 changed type(address) to type()
} }
@ -90,7 +91,14 @@ class SolidityVariable(Context):
# dev function, will be removed once the code is stable # dev function, will be removed once the code is stable
def _check_name(self, name: str): def _check_name(self, name: str):
assert name in SOLIDITY_VARIABLES assert name in SOLIDITY_VARIABLES or name.endswith("_slot") or name.endswith("_offset")
@property
def state_variable(self):
if self._name.endswith("_slot"):
return self._name[:-5]
if self._name.endswith("_offset"):
return self._name[:-7]
@property @property
def name(self) -> str: def name(self) -> str:

@ -31,6 +31,15 @@ class BinaryOperationType(Enum):
ANDAND = 17 # && ANDAND = 17 # &&
OROR = 18 # || OROR = 18 # ||
# YUL specific operators
# TODO: investigate if we can remove these
# Find the types earlier on, and do the conversion
DIVISION_SIGNED = 19
MODULO_SIGNED = 20
LESS_SIGNED = 21
GREATER_SIGNED = 22
RIGHT_SHIFT_ARITHMETIC = 23
@staticmethod @staticmethod
def get_type(operation_type: "BinaryOperation"): def get_type(operation_type: "BinaryOperation"):
if operation_type == "**": if operation_type == "**":
@ -71,6 +80,16 @@ class BinaryOperationType(Enum):
return BinaryOperationType.ANDAND return BinaryOperationType.ANDAND
if operation_type == "||": if operation_type == "||":
return BinaryOperationType.OROR return BinaryOperationType.OROR
if operation_type == "/'":
return BinaryOperationType.DIVISION_SIGNED
if operation_type == "%'":
return BinaryOperationType.MODULO_SIGNED
if operation_type == "<'":
return BinaryOperationType.LESS_SIGNED
if operation_type == ">'":
return BinaryOperationType.GREATER_SIGNED
if operation_type == ">>'":
return BinaryOperationType.RIGHT_SHIFT_ARITHMETIC
raise SlitherCoreError("get_type: Unknown operation type {})".format(operation_type)) raise SlitherCoreError("get_type: Unknown operation type {})".format(operation_type))
@ -113,6 +132,16 @@ class BinaryOperationType(Enum):
return "&&" return "&&"
if self == BinaryOperationType.OROR: if self == BinaryOperationType.OROR:
return "||" return "||"
if self == BinaryOperationType.DIVISION_SIGNED:
return "/'"
if self == BinaryOperationType.MODULO_SIGNED:
return "%'"
if self == BinaryOperationType.LESS_SIGNED:
return "<'"
if self == BinaryOperationType.GREATER_SIGNED:
return ">'"
if self == BinaryOperationType.RIGHT_SHIFT_ARITHMETIC:
return ">>'"
raise SlitherCoreError("str: Unknown operation type {})".format(self)) raise SlitherCoreError("str: Unknown operation type {})".format(self))

@ -41,14 +41,6 @@ class CallExpression(Expression):
def call_salt(self, salt): def call_salt(self, salt):
self._salt = salt self._salt = salt
@property
def call_salt(self):
return self._salt
@call_salt.setter
def call_salt(self, salt):
self._salt = salt
@property @property
def called(self) -> Expression: def called(self) -> Expression:
return self._called return self._called

@ -15,5 +15,10 @@ class ElementaryTypeNameExpression(Expression):
def type(self) -> Type: def type(self) -> Type:
return self._type return self._type
@type.setter
def type(self, new_type: Type):
assert isinstance(new_type, Type)
self._type = new_type
def __str__(self): def __str__(self):
return str(self._type) return str(self._type)

@ -5,13 +5,14 @@ import os
import logging import logging
import json import json
import re import re
import math
from collections import defaultdict from collections import defaultdict
from typing import Optional, Dict, List, Set, Union from typing import Optional, Dict, List, Set, Union, Tuple
from crytic_compile import CryticCompile from crytic_compile import CryticCompile
from slither.core.context.context import Context from slither.core.context.context import Context
from slither.core.declarations import Contract, Pragma, Import, Function, Modifier from slither.core.declarations import Contract, Pragma, Import, Function, Modifier, Structure, Enum
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
from slither.slithir.operations import InternalCall from slither.slithir.operations import InternalCall
from slither.slithir.variables import Constant from slither.slithir.variables import Constant
@ -56,6 +57,11 @@ class SlitherCore(Context):
self._contract_name_collisions = defaultdict(list) self._contract_name_collisions = defaultdict(list)
self._contract_with_missing_inheritance = set() self._contract_with_missing_inheritance = set()
self._storage_layouts: Dict[str, Dict[str, Tuple[int, int]]] = {}
# If set to true, slither will not catch errors during parsing
self._disallow_partial: bool = False
################################################################################### ###################################################################################
################################################################################### ###################################################################################
# region Source code # region Source code
@ -136,7 +142,7 @@ class SlitherCore(Context):
"""list(Contract): List of contracts that are derived and not inherited.""" """list(Contract): List of contracts that are derived and not inherited."""
inheritance = (x.inheritance for x in self.contracts) inheritance = (x.inheritance for x in self.contracts)
inheritance = [item for sublist in inheritance for item in sublist] inheritance = [item for sublist in inheritance for item in sublist]
return [c for c in self._contracts.values() if c not in inheritance] return [c for c in self._contracts.values() if c not in inheritance and not c.is_top_level]
@property @property
def contracts_as_dict(self) -> Dict[str, Contract]: def contracts_as_dict(self) -> Dict[str, Contract]:
@ -200,6 +206,23 @@ class SlitherCore(Context):
self._all_state_variables = set(state_variables) self._all_state_variables = set(state_variables)
return list(self._all_state_variables) return list(self._all_state_variables)
# endregion
###################################################################################
###################################################################################
# region Top level
###################################################################################
###################################################################################
@property
def top_level_structures(self) -> List[Structure]:
top_level_structures = [c.structures for c in self.contracts if c.is_top_level]
return [st for sublist in top_level_structures for st in sublist]
@property
def top_level_enums(self) -> List[Enum]:
top_level_enums = [c.enums for c in self.contracts if c.is_top_level]
return [st for sublist in top_level_enums for st in sublist]
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################
@ -344,4 +367,50 @@ class SlitherCore(Context):
def contracts_with_missing_inheritance(self) -> Set: def contracts_with_missing_inheritance(self) -> Set:
return self._contract_with_missing_inheritance return self._contract_with_missing_inheritance
@property
def disallow_partial(self) -> bool:
"""
Return true if partial analyses are disallowed
For example, codebase with duplicate names will lead to partial analyses
:return:
"""
return self._disallow_partial
# endregion
###################################################################################
###################################################################################
# region Storage Layouts
###################################################################################
###################################################################################
def compute_storage_layout(self):
for contract in self.contracts_derived:
self._storage_layouts[contract.name] = {}
slot = 0
offset = 0
for var in contract.state_variables_ordered:
if var.is_constant:
continue
size, new_slot = var.type.storage_size
if new_slot:
if offset > 0:
slot += 1
offset = 0
elif size + offset > 32:
slot += 1
offset = 0
self._storage_layouts[contract.name][var.canonical_name] = (slot, offset)
if new_slot:
slot += math.ceil(size / 32)
else:
offset += size
def storage_layout_of(self, contract, var) -> Tuple[int, int]:
return self._storage_layouts[contract.name][var.canonical_name]
# endregion # endregion

@ -1,4 +1,4 @@
from typing import Optional from typing import Optional, Tuple
from slither.core.expressions import Literal from slither.core.expressions import Literal
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
@ -37,6 +37,13 @@ class ArrayType(Type):
def lenght_value(self) -> Optional[Literal]: def lenght_value(self) -> Optional[Literal]:
return self._length_value return self._length_value
@property
def storage_size(self) -> Tuple[int, bool]:
if self._length_value:
elem_size, _ = self._type.storage_size
return elem_size * int(self._length_value.value), True
return 32, True
def __str__(self): def __str__(self):
if self._length: if self._length:
return str(self._type) + "[{}]".format(str(self._length_value)) return str(self._type) + "[{}]".format(str(self._length_value))

@ -1,5 +1,5 @@
import itertools import itertools
from typing import Optional from typing import Optional, Tuple
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
@ -172,6 +172,13 @@ class ElementaryType(Type):
return int(t[len("bytes") :]) return int(t[len("bytes") :])
return None return None
@property
def storage_size(self) -> Tuple[int, bool]:
if self._type == "string" or self._type == "bytes":
return 32, True
return int(self.size / 8), False
def __str__(self): def __str__(self):
return self._type return self._type

@ -1,4 +1,4 @@
from typing import List from typing import List, Tuple
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.core.variables.function_type_variable import FunctionTypeVariable from slither.core.variables.function_type_variable import FunctionTypeVariable
@ -26,6 +26,10 @@ class FunctionType(Type):
def return_type(self) -> List[Type]: def return_type(self) -> List[Type]:
return [x.type for x in self.return_values] return [x.type for x in self.return_values]
@property
def storage_size(self) -> Tuple[int, bool]:
return 24, False
def __str__(self): def __str__(self):
# Use x.type # Use x.type
# x.name may be empty # x.name may be empty

@ -1,3 +1,5 @@
from typing import Tuple
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
@ -17,6 +19,10 @@ class MappingType(Type):
def type_to(self) -> Type: def type_to(self) -> Type:
return self._to return self._to
@property
def storage_size(self) -> Tuple[int, bool]:
return 32, True
def __str__(self): def __str__(self):
return "mapping({} => {})".format(str(self._from), str(self._to)) return "mapping({} => {})".format(str(self._from), str(self._to))

@ -1,5 +1,16 @@
import abc
from typing import Tuple
from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.source_mapping.source_mapping import SourceMapping
class Type(SourceMapping): class Type(SourceMapping, metaclass=abc.ABCMeta):
pass @property
@abc.abstractmethod
def storage_size(self) -> Tuple[int, bool]:
"""
Computes and returns storage layout related metadata
:return: (int, bool) - the number of bytes this type will require, and whether it must start in
a new slot regardless of whether the current slot can still fit it
"""

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING, Tuple
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
@ -20,6 +20,18 @@ class TypeInformation(Type):
def type(self) -> "Contract": def type(self) -> "Contract":
return self._type return self._type
@property
def storage_size(self) -> Tuple[int, bool]:
"""
32 is incorrect, as Type(x) return a kind of structure that can contain
an arbitrary number of value
As Type(x) cannot be directly stored, we are assuming that the correct storage size
will be handled by the fields access
:return:
"""
return 32, True
def __str__(self): def __str__(self):
return f"type({self.type.name})" return f"type({self.type.name})"

@ -1,4 +1,5 @@
from typing import Union, TYPE_CHECKING from typing import Union, TYPE_CHECKING, Tuple
import math
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
@ -22,6 +23,38 @@ class UserDefinedType(Type):
def type(self) -> Union["Contract", "Enum", "Structure"]: def type(self) -> Union["Contract", "Enum", "Structure"]:
return self._type return self._type
@property
def storage_size(self) -> Tuple[int, bool]:
from slither.core.declarations.structure import Structure
from slither.core.declarations.enum import Enum
from slither.core.declarations.contract import Contract
if isinstance(self._type, Contract):
return 20, False
elif isinstance(self._type, Enum):
return int(math.ceil(math.log2(len(self._type.values)) / 8)), False
elif isinstance(self._type, Structure):
# todo there's some duplicate logic here and slither_core, can we refactor this?
slot = 0
offset = 0
for elem in self._type.elems_ordered:
size, new_slot = elem.type.storage_size
if new_slot:
if offset > 0:
slot += 1
offset = 0
elif size + offset > 32:
slot += 1
offset = 0
if new_slot:
slot += math.ceil(size / 32)
else:
offset += size
if offset > 0:
slot += 1
return slot * 32, True
def __str__(self): def __str__(self):
from slither.core.declarations.structure import Structure from slither.core.declarations.structure import Structure
from slither.core.declarations.enum import Enum from slither.core.declarations.enum import Enum

@ -186,7 +186,7 @@ class AbstractDetector(metaclass=abc.ABCMeta):
if results and self.slither.triage_mode: if results and self.slither.triage_mode:
while True: while True:
indexes = input( indexes = input(
'Results to hide during next runs: "0,1,..." or "All" (enter to not hide results): '.format( 'Results to hide during next runs: "0,1,...,{}" or "All" (enter to not hide results): '.format(
len(results) len(results)
) )
) )

@ -22,7 +22,7 @@ class ConstantFunctionsAsm(AbstractDetector):
WIKI_DESCRIPTION = """ WIKI_DESCRIPTION = """
Functions declared as `constant`/`pure`/`view` using assembly code. Functions declared as `constant`/`pure`/`view` using assembly code.
`constant`/`pure`/`view` was not enforced prior Solidity 0.5. `constant`/`pure`/`view` was not enforced prior to Solidity 0.5.
Starting from Solidity 0.5, a call to a `constant`/`pure`/`view` function uses the `STATICCALL` opcode, which reverts in case of state modification. Starting from Solidity 0.5, a call to a `constant`/`pure`/`view` function uses the `STATICCALL` opcode, which reverts in case of state modification.
As a result, a call to an [incorrectly labeled function may trap a contract compiled with Solidity 0.5](https://solidity.readthedocs.io/en/develop/050-breaking-changes.html#interoperability-with-older-contracts).""" As a result, a call to an [incorrectly labeled function may trap a contract compiled with Solidity 0.5](https://solidity.readthedocs.io/en/develop/050-breaking-changes.html#interoperability-with-older-contracts)."""
@ -37,11 +37,11 @@ contract Constant{
} }
} }
``` ```
`Constant` was deployed with Solidity 0.4.25. Bob writes a smart contract interacting with `Constant` in Solidity 0.5.0. `Constant` was deployed with Solidity 0.4.25. Bob writes a smart contract that interacts with `Constant` in Solidity 0.5.0.
All the calls to `get` revert, breaking Bob's smart contract execution.""" All the calls to `get` revert, breaking Bob's smart contract execution."""
WIKI_RECOMMENDATION = ( WIKI_RECOMMENDATION = (
"Ensure that the attributes of contracts compiled prior to Solidity 0.5.0 are correct." "Ensure the attributes of contracts compiled prior to Solidity 0.5.0 are correct."
) )
def _detect(self): def _detect(self):

@ -20,9 +20,9 @@ class ConstantFunctionsState(AbstractDetector):
WIKI_TITLE = "Constant functions changing the state" WIKI_TITLE = "Constant functions changing the state"
WIKI_DESCRIPTION = """ WIKI_DESCRIPTION = """
Functions declared as `constant`/`pure`/`view` changing the state. Functions declared as `constant`/`pure`/`view` change the state.
`constant`/`pure`/`view` was not enforced prior Solidity 0.5. `constant`/`pure`/`view` was not enforced prior to Solidity 0.5.
Starting from Solidity 0.5, a call to a `constant`/`pure`/`view` function uses the `STATICCALL` opcode, which reverts in case of state modification. Starting from Solidity 0.5, a call to a `constant`/`pure`/`view` function uses the `STATICCALL` opcode, which reverts in case of state modification.
As a result, a call to an [incorrectly labeled function may trap a contract compiled with Solidity 0.5](https://solidity.readthedocs.io/en/develop/050-breaking-changes.html#interoperability-with-older-contracts).""" As a result, a call to an [incorrectly labeled function may trap a contract compiled with Solidity 0.5](https://solidity.readthedocs.io/en/develop/050-breaking-changes.html#interoperability-with-older-contracts)."""
@ -37,11 +37,11 @@ contract Constant{
} }
} }
``` ```
`Constant` was deployed with Solidity 0.4.25. Bob writes a smart contract interacting with `Constant` in Solidity 0.5.0. `Constant` was deployed with Solidity 0.4.25. Bob writes a smart contract that interacts with `Constant` in Solidity 0.5.0.
All the calls to `get` revert, breaking Bob's smart contract execution.""" All the calls to `get` revert, breaking Bob's smart contract execution."""
WIKI_RECOMMENDATION = ( WIKI_RECOMMENDATION = (
"Ensure that the attributes of contracts compiled prior to Solidity 0.5.0 are correct." "Ensure that attributes of contracts compiled prior to Solidity 0.5.0 are correct."
) )
def _detect(self): def _detect(self):

@ -19,7 +19,7 @@ class ConstantPragma(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#different-pragma-directives-are-used" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#different-pragma-directives-are-used"
WIKI_TITLE = "Different pragma directives are used" WIKI_TITLE = "Different pragma directives are used"
WIKI_DESCRIPTION = "Detect if different Solidity versions are used." WIKI_DESCRIPTION = "Detect whether different Solidity versions are used."
WIKI_RECOMMENDATION = "Use one Solidity version." WIKI_RECOMMENDATION = "Use one Solidity version."
def _detect(self): def _detect(self):

@ -30,24 +30,40 @@ class IncorrectSolc(AbstractDetector):
WIKI_TITLE = "Incorrect versions of Solidity" WIKI_TITLE = "Incorrect versions of Solidity"
WIKI_DESCRIPTION = """ WIKI_DESCRIPTION = """
Solc frequently releases new compiler versions. Using an old version prevents access to new Solidity security checks. `solc` frequently releases new compiler versions. Using an old version prevents access to new Solidity security checks.
We recommend avoiding complex pragma statement.""" We also recommend avoiding complex `pragma` statement."""
WIKI_RECOMMENDATION = """ WIKI_RECOMMENDATION = """
Use Solidity 0.4.25 or 0.5.11. Consider using the latest version of Solidity for testing the compilation, and a trusted version for deploying.""" Deploy with any of the following Solidity versions:
- 0.5.11 - 0.5.13,
- 0.5.15 - 0.5.17,
- 0.6.8,
- 0.6.10 - 0.6.11.
Use a simple pragma version that allows any of these versions.
Consider using the latest version of Solidity for testing."""
COMPLEX_PRAGMA_TXT = "is too complex" COMPLEX_PRAGMA_TXT = "is too complex"
OLD_VERSION_TXT = "allows old versions" OLD_VERSION_TXT = "allows old versions"
LESS_THAN_TXT = "uses lesser than" LESS_THAN_TXT = "uses lesser than"
TOO_RECENT_VERSION_TXT = ( TOO_RECENT_VERSION_TXT = (
"necessitates versions too recent to be trusted. Consider deploying with 0.5.11" "necessitates a version too recent to be trusted. Consider deploying with 0.6.11"
) )
BUGGY_VERSION_TXT = ( BUGGY_VERSION_TXT = (
"is known to contain severe issue (https://solidity.readthedocs.io/en/v0.5.8/bugs.html)" "is known to contain severe issues (https://solidity.readthedocs.io/en/latest/bugs.html)"
) )
# Indicates the allowed versions. Must be formatted in increasing order. # Indicates the allowed versions. Must be formatted in increasing order.
ALLOWED_VERSIONS = ["0.4.25", "0.4.26", "0.5.11"] ALLOWED_VERSIONS = [
"0.5.11",
"0.5.12",
"0.5.13",
"0.5.15",
"0.5.16",
"0.5.17",
"0.6.8",
"0.6.10",
"0.6.11",
]
# Indicates the versions that should not be used. # Indicates the versions that should not be used.
BUGGY_VERSIONS = [ BUGGY_VERSIONS = [
@ -59,6 +75,8 @@ Use Solidity 0.4.25 or 0.5.11. Consider using the latest version of Solidity for
"^0.5.6", "^0.5.6",
"0.5.14", "0.5.14",
"^0.5.14", "^0.5.14",
"0.6.9",
"^0.6.9",
] ]
def _check_version(self, version): def _check_version(self, version):
@ -124,6 +142,22 @@ Use Solidity 0.4.25 or 0.5.11. Consider using the latest version of Solidity for
results.append(json) results.append(json)
if self.slither.crytic_compile:
if self.slither.crytic_compile.compiler_version:
if (
self.slither.crytic_compile.compiler_version.version
not in self.ALLOWED_VERSIONS
):
info = [
"solc-",
self.slither.crytic_compile.compiler_version.version,
" is not recommended for deployement\n",
]
json = self.generate_result(info)
results.append(json)
return results return results
@staticmethod @staticmethod

@ -25,8 +25,8 @@ class LockedEther(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#contracts-that-lock-ether" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#contracts-that-lock-ether"
WIKI_TITLE = "Contracts that lock ether" WIKI_TITLE = "Contracts that lock Ether"
WIKI_DESCRIPTION = "Contract with a `payable` function, but without a withdraw capacity." WIKI_DESCRIPTION = "Contract with a `payable` function, but without a withdrawal capacity."
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
pragma solidity 0.4.24; pragma solidity 0.4.24;
@ -35,7 +35,7 @@ contract Locked{
} }
} }
``` ```
Every ether sent to `Locked` will be lost.""" Every Ether sent to `Locked` will be lost."""
WIKI_RECOMMENDATION = "Remove the payable attribute or add a withdraw function." WIKI_RECOMMENDATION = "Remove the payable attribute or add a withdraw function."

@ -18,7 +18,7 @@ class IncorrectERC20InterfaceDetection(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface"
WIKI_TITLE = "Incorrect erc20 interface" WIKI_TITLE = "Incorrect erc20 interface"
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_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 = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract Token{ contract Token{
@ -26,10 +26,10 @@ 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.""" `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 = ( WIKI_RECOMMENDATION = (
"Set the appropriate return values and value-types for the defined ERC20 functions." "Set the appropriate return values and types for the defined `ERC20` functions."
) )
@staticmethod @staticmethod

@ -19,7 +19,7 @@ class IncorrectERC721InterfaceDetection(AbstractDetector):
) )
WIKI_TITLE = "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_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 = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract Token{ contract Token{
@ -27,10 +27,10 @@ contract Token{
//... //...
} }
``` ```
`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.""" `Token.ownerOf` does not return an address like `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 = ( WIKI_RECOMMENDATION = (
"Set the appropriate return values and value-types for the defined ERC721 functions." "Set the appropriate return values and vtypes for the defined `ERC721` functions."
) )
@staticmethod @staticmethod

@ -16,8 +16,8 @@ class UnindexedERC20EventParameters(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#unindexed-erc20-event-parameters" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#unindexed-erc20-event-parameters"
WIKI_TITLE = "Unindexed ERC20 Event Parameters" WIKI_TITLE = "Unindexed ERC20 event oarameters"
WIKI_DESCRIPTION = "Detects that events defined by the ERC20 specification which are meant to have some parameters as `indexed`, are missing the `indexed` keyword." WIKI_DESCRIPTION = "Detects whether events defined by the `ERC20` specification that should have some parameters as `indexed` are missing the `indexed` keyword."
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract ERC20Bad { contract ERC20Bad {
@ -28,9 +28,10 @@ contract ERC20Bad {
// ... // ...
} }
``` ```
In this case, Transfer and Approval events should have the 'indexed' keyword on their two first parameters, as defined by the ERC20 specification. Failure to include these keywords will not include the parameter data in the transaction/block's bloom filter. This may cause external tooling searching for these parameters to overlook them, and fail to index logs from this token contract.""" `Transfer` and `Approval` events should have the 'indexed' keyword on their two first parameters, as defined by the `ERC20` specification.
Failure to include these keywords will exclude the parameter data in the transaction/block's bloom filter, so external tooling searching for these parameters may overlook them and fail to index logs from this token contract."""
WIKI_RECOMMENDATION = "Add the `indexed` keyword to event parameters which should include it, according to the ERC20 specification." WIKI_RECOMMENDATION = "Add the `indexed` keyword to event parameters that should include it, according to the `ERC20` specification."
STANDARD_JSON = False STANDARD_JSON = False

@ -28,16 +28,14 @@ class ArbitrarySend(AbstractDetector):
""" """
ARGUMENT = "arbitrary-send" ARGUMENT = "arbitrary-send"
HELP = "Functions that send ether to arbitrary destinations" HELP = "Functions that send Ether to arbitrary destinations"
IMPACT = DetectorClassification.HIGH IMPACT = DetectorClassification.HIGH
CONFIDENCE = DetectorClassification.MEDIUM CONFIDENCE = DetectorClassification.MEDIUM
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#functions-that-send-ether-to-arbitrary-destinations" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#functions-that-send-ether-to-arbitrary-destinations"
WIKI_TITLE = "Functions that send ether to arbitrary destinations" WIKI_TITLE = "Functions that send Ether to arbitrary destinations"
WIKI_DESCRIPTION = ( WIKI_DESCRIPTION = "Unprotected call to a function sending Ether to an arbitrary address."
"Unprotected call to a function executing sending ethers to an arbitrary address."
)
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract ArbitrarySend{ contract ArbitrarySend{
@ -53,7 +51,7 @@ contract ArbitrarySend{
``` ```
Bob calls `setDestination` and `withdraw`. As a result he withdraws the contract's balance.""" Bob calls `setDestination` and `withdraw`. As a result he withdraws the contract's balance."""
WIKI_RECOMMENDATION = "Ensure that an arbitrary user cannot withdraw unauthorize funds." WIKI_RECOMMENDATION = "Ensure that an arbitrary user cannot withdraw unauthorized funds."
def arbitrary_send(self, func): def arbitrary_send(self, func):
""" """

@ -13,13 +13,13 @@ class ExternalFunction(AbstractDetector):
""" """
ARGUMENT = "external-function" ARGUMENT = "external-function"
HELP = "Public function that could be declared as external" HELP = "Public function that could be declared external"
IMPACT = DetectorClassification.OPTIMIZATION IMPACT = DetectorClassification.OPTIMIZATION
CONFIDENCE = DetectorClassification.HIGH CONFIDENCE = DetectorClassification.HIGH
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#public-function-that-could-be-declared-as-external" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#public-function-that-could-be-declared-external"
WIKI_TITLE = "Public function that could be declared as external" WIKI_TITLE = "Public function that could be declared external"
WIKI_DESCRIPTION = "`public` functions that are never called by the contract should be declared `external` to save gas." WIKI_DESCRIPTION = "`public` functions that are never called by the contract should be declared `external` to save gas."
WIKI_RECOMMENDATION = ( WIKI_RECOMMENDATION = (
"Use the `external` attribute for functions never called from the contract." "Use the `external` attribute for functions never called from the contract."

@ -45,7 +45,7 @@ Bob calls `kill` and destructs the contract."""
if func.is_constructor: if func.is_constructor:
return False return False
if func.visibility != "public": if func.visibility not in ["public", "external"]:
return False return False
calls = [c.name for c in func.internal_calls] calls = [c.name for c in func.internal_calls]
@ -59,7 +59,7 @@ Bob calls `kill` and destructs the contract."""
def detect_suicidal(self, contract): def detect_suicidal(self, contract):
ret = [] ret = []
for f in [f for f in contract.functions if f.contract_declarer == contract]: for f in contract.functions_declared:
if self.detect_suicidal_func(f): if self.detect_suicidal_func(f):
ret.append(f) ret.append(f)
return ret return ret

@ -15,18 +15,18 @@ class NamingConvention(AbstractDetector):
""" """
ARGUMENT = "naming-convention" ARGUMENT = "naming-convention"
HELP = "Conformance to Solidity naming conventions" HELP = "Conformity to Solidity naming conventions"
IMPACT = DetectorClassification.INFORMATIONAL IMPACT = DetectorClassification.INFORMATIONAL
CONFIDENCE = DetectorClassification.HIGH CONFIDENCE = DetectorClassification.HIGH
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#conformance-to-solidity-naming-conventions" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#conformity-to-solidity-naming-conventions"
WIKI_TITLE = "Conformance to Solidity naming conventions" WIKI_TITLE = "Conformance to Solidity naming conventions"
WIKI_DESCRIPTION = """ WIKI_DESCRIPTION = """
Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.25/style-guide.html#naming-conventions) that should be followed. Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.25/style-guide.html#naming-conventions) that should be followed.
#### Rules exceptions #### Rule exceptions
- Allow constant variables name/symbol/decimals to be lowercase (ERC20) - Allow constant variable name/symbol/decimals to be lowercase (`ERC20`).
- Allow `_` at the beginning of the mixed_case match for private variables and unused parameters.""" - Allow `_` at the beginning of the `mixed_case` match for private variables and unused parameters."""
WIKI_RECOMMENDATION = "Follow the Solidity [naming convention](https://solidity.readthedocs.io/en/v0.4.25/style-guide.html#naming-conventions)." WIKI_RECOMMENDATION = "Follow the Solidity [naming convention](https://solidity.readthedocs.io/en/v0.4.25/style-guide.html#naming-conventions)."

@ -18,7 +18,7 @@ class LowLevelCalls(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#low-level-calls" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#low-level-calls"
WIKI_TITLE = "Low level calls" WIKI_TITLE = "Low-level calls"
WIKI_DESCRIPTION = "The use of low-level calls is error-prone. Low-level calls do not check for [code existence](https://solidity.readthedocs.io/en/v0.4.25/control-structures.html#error-handling-assert-require-revert-and-exceptions) or call success." WIKI_DESCRIPTION = "The use of low-level calls is error-prone. Low-level calls do not check for [code existence](https://solidity.readthedocs.io/en/v0.4.25/control-structures.html#error-handling-assert-require-revert-and-exceptions) or call success."
WIKI_RECOMMENDATION = "Avoid low-level calls. Check the call success. If the call is meant for a contract, check for code existence." WIKI_RECOMMENDATION = "Avoid low-level calls. Check the call success. If the call is meant for a contract, check for code existence."

@ -28,11 +28,11 @@ contract MyConc{
} }
} }
``` ```
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. The return value of the low-level call is not checked, so if the call fails, the Ether will be locked in the contract.
If the low level is used to prevent blocking operations, consider logging failed calls. 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." WIKI_RECOMMENDATION = "Ensure that the return value of a low-level call is checked or logged."
_txt_description = "low-level calls" _txt_description = "low-level calls"

@ -20,7 +20,7 @@ class UncheckedSend(UnusedReturnValues):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-send" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-send"
WIKI_TITLE = "Unchecked Send" WIKI_TITLE = "Unchecked Send"
WIKI_DESCRIPTION = "The return value of a send is not checked." WIKI_DESCRIPTION = "The return value of a `send` is not checked."
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract MyConc{ contract MyConc{
@ -29,11 +29,11 @@ contract MyConc{
} }
} }
``` ```
The return value of `send` is not checked. As a result if the send failed, the ether will be locked in the contract. The return value of `send` is not checked, so if the send fails, the Ether will be locked in the contract.
If `send` is used to prevent blocking operations, consider logging the failed sent. If `send` is used to prevent blocking operations, consider logging the failed `send`.
""" """
WIKI_RECOMMENDATION = "Ensure that the return value of send is checked or logged." WIKI_RECOMMENDATION = "Ensure that the return value of `send` is checked or logged."
_txt_description = "send calls" _txt_description = "send calls"

@ -32,7 +32,7 @@ contract MyConc{
} }
} }
``` ```
`MyConc` calls `add` of SafeMath, but does not store the result in `a`. As a result, the computation has no effect.""" `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 used." WIKI_RECOMMENDATION = "Ensure that all the return values of the function calls are used."

@ -11,8 +11,8 @@ class VoidConstructor(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#void-constructor" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#void-constructor"
WIKI_TITLE = "Void Constructor" WIKI_TITLE = "Void constructor"
WIKI_DESCRIPTION = "Detect the call to a constructor not implemented" WIKI_DESCRIPTION = "Detect the call to a constructor that is not implemented"
WIKI_RECOMMENDATION = "Remove the constructor call." WIKI_RECOMMENDATION = "Remove the constructor call."
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
@ -21,7 +21,7 @@ contract B is A{
constructor() public A(){} constructor() public A(){}
} }
``` ```
By reading B's constructor definition, the reader might assume that `A()` initiate the contract, while no code is executed.""" When reading `B`'s constructor definition, we might assume that `A()` initiates the contract, but no code is executed."""
def _detect(self): def _detect(self):
""" """

@ -26,7 +26,7 @@ class ReentrancyBenign(Reentrancy):
WIKI_TITLE = "Reentrancy vulnerabilities" WIKI_TITLE = "Reentrancy vulnerabilities"
WIKI_DESCRIPTION = """ WIKI_DESCRIPTION = """
Detection of the [re-entrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy). Detection of the [reentrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy).
Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentrancy-no-eth`).""" Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentrancy-no-eth`)."""
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
@ -40,7 +40,7 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
`callme` contains a reentrancy. The reentrancy is benign because it's exploitation would have the same effect as two consecutive calls.""" `callme` contains a reentrancy. The reentrancy is benign because it's exploitation would have the same effect as two consecutive calls."""
WIKI_RECOMMENDATION = "Apply the [check-effects-interactions pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)." WIKI_RECOMMENDATION = "Apply the [`check-effects-interactions` pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)."
STANDARD_JSON = False STANDARD_JSON = False

@ -26,12 +26,12 @@ class ReentrancyEth(Reentrancy):
WIKI_TITLE = "Reentrancy vulnerabilities" WIKI_TITLE = "Reentrancy vulnerabilities"
WIKI_DESCRIPTION = """ WIKI_DESCRIPTION = """
Detection of the [re-entrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy). Detection of the [reentrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy).
Do not report reentrancies that don't involve ethers (see `reentrancy-no-eth`)""" Do not report reentrancies that don't involve Ether (see `reentrancy-no-eth`)"""
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
function withdrawBalance(){ function withdrawBalance(){
// send userBalance[msg.sender] ethers to msg.sender // send userBalance[msg.sender] Ether to msg.sender
// if mgs.sender is a contract, it will call its fallback function // if mgs.sender is a contract, it will call its fallback function
if( ! (msg.sender.call.value(userBalance[msg.sender])() ) ){ if( ! (msg.sender.call.value(userBalance[msg.sender])() ) ){
throw; throw;
@ -42,7 +42,7 @@ Do not report reentrancies that don't involve ethers (see `reentrancy-no-eth`)""
Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw more than its initial deposit to the contract.""" Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw more than its initial deposit to the contract."""
WIKI_RECOMMENDATION = "Apply the [check-effects-interactions pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)." WIKI_RECOMMENDATION = "Apply the [`check-effects-interactions pattern`](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)."
STANDARD_JSON = False STANDARD_JSON = False

@ -25,8 +25,8 @@ class ReentrancyEvent(Reentrancy):
WIKI_TITLE = "Reentrancy vulnerabilities" WIKI_TITLE = "Reentrancy vulnerabilities"
WIKI_DESCRIPTION = """ WIKI_DESCRIPTION = """
Detection of the [re-entrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy). Detection of the [reentrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy).
Only report reentrancies leading to out-of-order Events""" Only report reentrancies leading to out-of-order events."""
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
function bug(Called d){ function bug(Called d){
@ -36,9 +36,9 @@ Only report reentrancies leading to out-of-order Events"""
} }
``` ```
If `d.()` reenters, the `Counter` events will be showed in an incorrect order, which might lead to issues for third-parties.""" If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, which might lead to issues for third parties."""
WIKI_RECOMMENDATION = "Apply the [check-effects-interactions pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)." WIKI_RECOMMENDATION = "Apply the [`check-effects-interactions` pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)."
STANDARD_JSON = False STANDARD_JSON = False
@ -85,7 +85,7 @@ If `d.()` reenters, the `Counter` events will be showed in an incorrect order, w
for (func, calls, send_eth), events in result_sorted: for (func, calls, send_eth), events in result_sorted:
calls = sorted(list(set(calls)), key=lambda x: x[0].node_id) calls = sorted(list(set(calls)), key=lambda x: x[0].node_id)
send_eth = sorted(list(set(send_eth)), key=lambda x: x[0].node_id) send_eth = sorted(list(set(send_eth)), key=lambda x: x[0].node_id)
events = sorted(events, key=lambda x: (x.variable.name, x.node.node_id)) events = sorted(events, key=lambda x: (str(x.variable.name), x.node.node_id))
info = ["Reentrancy in ", func, ":\n"] info = ["Reentrancy in ", func, ":\n"]
info += ["\tExternal calls:\n"] info += ["\tExternal calls:\n"]

@ -29,8 +29,8 @@ class ReentrancyNoGas(Reentrancy):
WIKI_TITLE = "Reentrancy vulnerabilities" WIKI_TITLE = "Reentrancy vulnerabilities"
WIKI_DESCRIPTION = """ WIKI_DESCRIPTION = """
Detection of the [re-entrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy). Detection of the [reentrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy).
Only report reentrancy that are based on `transfer` or `send`.""" Only report reentrancy that is based on `transfer` or `send`."""
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
function callme(){ function callme(){
@ -39,9 +39,9 @@ Only report reentrancy that are based on `transfer` or `send`."""
} }
``` ```
`send` and `transfer` does not protect from reentrancies in case of gas-price change.""" `send` and `transfer` do not protect from reentrancies in case of gas price changes."""
WIKI_RECOMMENDATION = "Apply the [check-effects-interactions pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)." WIKI_RECOMMENDATION = "Apply the [`check-effects-interactions` pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)."
@staticmethod @staticmethod
def can_callback(ir): def can_callback(ir):

@ -25,8 +25,8 @@ class ReentrancyReadBeforeWritten(Reentrancy):
WIKI_TITLE = "Reentrancy vulnerabilities" WIKI_TITLE = "Reentrancy vulnerabilities"
WIKI_DESCRIPTION = """ WIKI_DESCRIPTION = """
Detection of the [re-entrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy). Detection of the [reentrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy).
Do not report reentrancies that involve ethers (see `reentrancy-eth`)""" Do not report reentrancies that involve Ether (see `reentrancy-eth`)."""
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
@ -39,7 +39,7 @@ Do not report reentrancies that involve ethers (see `reentrancy-eth`)"""
} }
``` ```
""" """
WIKI_RECOMMENDATION = "Apply the [check-effects-interactions pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)." WIKI_RECOMMENDATION = "Apply the [`check-effects-interactions` pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)."
STANDARD_JSON = False STANDARD_JSON = False

@ -18,7 +18,7 @@ class BuiltinSymbolShadowing(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#builtin-symbol-shadowing" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#builtin-symbol-shadowing"
WIKI_TITLE = "Builtin Symbol Shadowing" WIKI_TITLE = "Builtin Symbol Shadowing"
WIKI_DESCRIPTION = "Detection of shadowing built-in symbols using local variables/state variables/functions/modifiers/events." WIKI_DESCRIPTION = "Detection of shadowing built-in symbols using local variables, state variables, functions, modifiers, or events."
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
pragma solidity ^0.4.24; pragma solidity ^0.4.24;
@ -37,7 +37,7 @@ contract Bug {
``` ```
`now` is defined as a state variable, and shadows with the built-in symbol `now`. The function `assert` overshadows the built-in `assert` function. Any use of either of these built-in symbols may lead to unexpected results.""" `now` is defined as a state variable, and shadows with the built-in symbol `now`. The function `assert` overshadows the built-in `assert` function. Any use of either of these built-in symbols may lead to unexpected results."""
WIKI_RECOMMENDATION = "Rename the local variable/state variable/function/modifier/event, so as not to mistakenly overshadow any built-in symbol definitions." WIKI_RECOMMENDATION = "Rename the local variables, state variables, functions, modifiers, and events that shadow a builtin symbol."
SHADOWING_FUNCTION = "function" SHADOWING_FUNCTION = "function"
SHADOWING_MODIFIER = "modifier" SHADOWING_MODIFIER = "modifier"

@ -17,7 +17,7 @@ class LocalShadowing(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#local-variable-shadowing" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#local-variable-shadowing"
WIKI_TITLE = "Local Variable Shadowing" WIKI_TITLE = "Local variable shadowing"
WIKI_DESCRIPTION = "Detection of shadowing using local variables." WIKI_DESCRIPTION = "Detection of shadowing using local variables."
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
@ -38,9 +38,9 @@ contract Bug {
} }
} }
``` ```
`sensitive_function.owner` shadows `Bug.owner`. As a result, the use of `owner` inside `sensitive_function` might be incorrect.""" `sensitive_function.owner` shadows `Bug.owner`. As a result, the use of `owner` in `sensitive_function` might be incorrect."""
WIKI_RECOMMENDATION = "Rename the local variable so as not to mistakenly overshadow any state variable/function/modifier/event definitions." WIKI_RECOMMENDATION = "Rename the local variables that shadow another component."
OVERSHADOWED_FUNCTION = "function" OVERSHADOWED_FUNCTION = "function"
OVERSHADOWED_MODIFIER = "modifier" OVERSHADOWED_MODIFIER = "modifier"

@ -33,11 +33,11 @@ class NameReused(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#name-reused" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#name-reused"
WIKI_TITLE = "Name reused" WIKI_TITLE = "Name reused"
WIKI_DESCRIPTION = """If a codebase has two contracts with the similar name, the compilation artifacts WIKI_DESCRIPTION = """If a codebase has two contracts the similar names, the compilation artifacts
will not contain one of the contract with the dupplicate name.""" will not contain one of the contracts with the duplicate name."""
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
Bob's truffle codebase has two contracts named `ERC20`. Bob's `truffle` codebase has two contracts named `ERC20`.
When `truffle compile` runs, only one of the two contract will generate artifacts in `build/contracts`. When `truffle compile` runs, only one of the two contracts will generate artifacts in `build/contracts`.
As a result, the second contract cannot be analyzed. As a result, the second contract cannot be analyzed.
""" """
WIKI_RECOMMENDATION = "Rename the contract." WIKI_RECOMMENDATION = "Rename the contract."

@ -13,8 +13,8 @@ class RightToLeftOverride(AbstractDetector):
CONFIDENCE = DetectorClassification.HIGH CONFIDENCE = DetectorClassification.HIGH
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#right-to-left-override-character" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#right-to-left-override-character"
WIKI_TITLE = "Right-To-Left-Override character" WIKI_TITLE = "Right-to-Left-Override character"
WIKI_DESCRIPTION = "An attacker can manipulate the logic of the contract by using a right-to-left-override character (U+202E)" WIKI_DESCRIPTION = "An attacker can manipulate the logic of the contract by using a right-to-left-override character (`U+202E)`."
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract Token contract Token

@ -20,7 +20,7 @@ class Assembly(AbstractDetector):
WIKI_TITLE = "Assembly usage" WIKI_TITLE = "Assembly usage"
WIKI_DESCRIPTION = "The use of assembly is error-prone and should be avoided." WIKI_DESCRIPTION = "The use of assembly is error-prone and should be avoided."
WIKI_RECOMMENDATION = "Do not use evm assembly." WIKI_RECOMMENDATION = "Do not use `evm` assembly."
@staticmethod @staticmethod
def _contains_inline_assembly_use(node): def _contains_inline_assembly_use(node):

@ -19,8 +19,8 @@ class BooleanEquality(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#boolean-equality" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#boolean-equality"
WIKI_TITLE = "Boolean Equality" WIKI_TITLE = "Boolean equality"
WIKI_DESCRIPTION = """Detects the comparison to boolean constant.""" WIKI_DESCRIPTION = """Detects the comparison to boolean constants."""
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract A { contract A {
@ -33,7 +33,7 @@ contract A {
} }
} }
``` ```
Boolean can be used directly and do not need to be compare to `true` or `false`.""" Boolean constants can be used directly and do not need to be compare to `true` or `false`."""
WIKI_RECOMMENDATION = """Remove the equality to the boolean constant.""" WIKI_RECOMMENDATION = """Remove the equality to the boolean constant."""

@ -52,7 +52,8 @@ contract A {
} }
} }
``` ```
Boolean constants in code have only a few legitimate uses. Other uses (in complex expressions, as conditionals) indicate either an error or (most likely) the persistence of debugging/development code that is likely faulty.""" Boolean constants in code have only a few legitimate uses.
Other uses (in complex expressions, as conditionals) indicate either an error or, most likely, the persistence of faulty code."""
WIKI_RECOMMENDATION = """Verify and simplify the condition.""" WIKI_RECOMMENDATION = """Verify and simplify the condition."""

@ -17,7 +17,7 @@ class MultipleCallsInLoop(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation/#calls-inside-a-loop" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation/#calls-inside-a-loop"
WIKI_TITLE = "Calls inside a loop" WIKI_TITLE = "Calls inside a loop"
WIKI_DESCRIPTION = "Calls inside a loop might lead to denial of service attack." WIKI_DESCRIPTION = "Calls inside a loop might lead to a denial-of-service attack."
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract CallsInLoop{ contract CallsInLoop{
@ -36,7 +36,7 @@ contract CallsInLoop{
} }
``` ```
If one of the destinations has a fallback function which reverts, `bad` will always revert.""" If one of the destinations has a fallback function that reverts, `bad` will always revert."""
WIKI_RECOMMENDATION = "Favor [pull over push](https://github.com/ethereum/wiki/wiki/Safety#favor-pull-over-push-for-external-calls) strategy for external calls." WIKI_RECOMMENDATION = "Favor [pull over push](https://github.com/ethereum/wiki/wiki/Safety#favor-pull-over-push-for-external-calls) strategy for external calls."

@ -15,7 +15,7 @@ class ControlledDelegateCall(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#controlled-delegatecall" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#controlled-delegatecall"
WIKI_TITLE = "Controlled Delegatecall" WIKI_TITLE = "Controlled Delegatecall"
WIKI_DESCRIPTION = "Delegatecall or callcode to an address controlled by the user." WIKI_DESCRIPTION = "`Delegatecall` or `callcode` to an address controlled by the user."
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract Delegatecall{ contract Delegatecall{
@ -24,7 +24,7 @@ contract Delegatecall{
} }
} }
``` ```
Bob calls `delegate` and delegates the execution to its malicious contract. As a result, Bob withdraws the funds of the contract and destructs it.""" Bob calls `delegate` and delegates the execution to his malicious contract. As a result, Bob withdraws the funds of the contract and destructs it."""
WIKI_RECOMMENDATION = "Avoid using `delegatecall`. Use only trusted destinations." WIKI_RECOMMENDATION = "Avoid using `delegatecall`. Use only trusted destinations."

@ -22,8 +22,8 @@ class DeprecatedStandards(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#deprecated-standards" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#deprecated-standards"
WIKI_TITLE = "Deprecated Standards" WIKI_TITLE = "Deprecated standards"
WIKI_DESCRIPTION = "Detect the usage of deprecated standards (as defined by SWC-111), excluding only `constant` keyword detection on functions." WIKI_DESCRIPTION = "Detect the usage of deprecated standards."
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract ContractWithDeprecatedReferences { contract ContractWithDeprecatedReferences {

@ -64,7 +64,7 @@ class DivideBeforeMultiply(AbstractDetector):
WIKI_TITLE = "Divide before multiply" WIKI_TITLE = "Divide before multiply"
WIKI_DESCRIPTION = """Solidity only supports integers, so division will often truncate; performing a multiply before a divison can sometimes avoid loss of precision.""" WIKI_DESCRIPTION = """Solidity only supports integers, so division will often truncate; performing a multiply before a divison can sometimes avoid loss of precision."""
WIKI_DESCRIPTION = """Solidity integer division might truncate. As a result, performing a multiply before a divison might lead to loss of precision.""" WIKI_DESCRIPTION = """Solidity integer division might truncate. As a result, performing multiplication before divison might reduce precision."""
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract A { contract A {
@ -75,9 +75,9 @@ contract A {
``` ```
If `n` is greater than `oldSupply`, `coins` will be zero. For example, with `oldSupply = 5; n = 10, interest = 2`, coins will be zero. If `n` is greater than `oldSupply`, `coins` will be zero. For example, with `oldSupply = 5; n = 10, interest = 2`, coins will be zero.
If `(oldSupply * interest / n)` was used, `coins` would have been `1`. If `(oldSupply * interest / n)` was used, `coins` would have been `1`.
In general, it's usually a good idea to re-arrange arithmetic to perform multiply before divide, unless the limit of a smaller type makes this dangerous.""" In general, it's usually a good idea to re-arrange arithmetic to perform multiplication before division, unless the limit of a smaller type makes this dangerous."""
WIKI_RECOMMENDATION = """Consider ordering multiplication prior division.""" WIKI_RECOMMENDATION = """Consider ordering multiplication before division."""
def _explore(self, node, explored, f_results, divisions): def _explore(self, node, explored, f_results, divisions):
if node in explored: if node in explored:

@ -33,10 +33,11 @@ contract Crowdsale{
return this.balance == 100 ether; return this.balance == 100 ether;
} }
``` ```
`Crowdsale` relies on `fund_reached` to know when to stop the sale of tokens. `Crowdsale` reaches 100 ether. Bob sends 0.1 ether. As a result, `fund_reached` is always false and the crowdsale never ends.""" `Crowdsale` relies on `fund_reached` to know when to stop the sale of tokens.
`Crowdsale` reaches 100 Ether. Bob sends 0.1 Ether. As a result, `fund_reached` is always false and the `crowdsale` never ends."""
WIKI_RECOMMENDATION = ( WIKI_RECOMMENDATION = (
"""Don't use strict equality to determine if an account has enough ethers or tokens.""" """Don't use strict equality to determine if an account has enough Ether or tokens."""
) )
sources_taint = [ sources_taint = [
@ -68,6 +69,7 @@ contract Crowdsale{
# TODO: fix Balance support # TODO: fix Balance support
taints.append(ir.lvalue) taints.append(ir.lvalue)
if isinstance(ir, HighLevelCall): if isinstance(ir, HighLevelCall):
# print(ir.function.full_name)
if ( if (
isinstance(ir.function, Function) isinstance(ir.function, Function)
and ir.function.full_name == "balanceOf(address)" and ir.function.full_name == "balanceOf(address)"

@ -28,11 +28,11 @@ contract MyContract{
} }
``` ```
While `1_ether` looks like `1 ether`, it is `10 ether`. As a result, its usage is likely to be incorrect. While `1_ether` looks like `1 ether`, it is `10 ether`. As a result, it's likely to be used incorrectly.
""" """
WIKI_RECOMMENDATION = """ WIKI_RECOMMENDATION = """
Use: Use:
- [Ether suffix](https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#ether-units) - [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 - [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) - [The scientific notation](https://solidity.readthedocs.io/en/latest/types.html#rational-and-integer-literals)
""" """

@ -20,7 +20,7 @@ class TxOrigin(AbstractDetector):
) )
WIKI_TITLE = "Dangerous usage of `tx.origin`" WIKI_TITLE = "Dangerous usage of `tx.origin`"
WIKI_DESCRIPTION = "`tx.origin`-based protection can be abused by malicious contract if a legitimate user interacts with the malicious contract." WIKI_DESCRIPTION = "`tx.origin`-based protection can be abused by a malicious contract if a legitimate user interacts with the malicious contract."
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract TxOrigin { contract TxOrigin {

@ -42,12 +42,12 @@ contract A {
} }
} }
``` ```
`x` is an `uint256`, as a result `x >= 0` will be always true. `x` is a `uint256`, so `x >= 0` will be always true.
`y` is an `uint8`, as a result `y <512` will be always true. `y` is a `uint8`, so `y <512` will be always true.
""" """
WIKI_RECOMMENDATION = ( WIKI_RECOMMENDATION = (
"""Fix the incorrect comparison by chaning the value type or the comparison.""" """Fix the incorrect comparison by changing the value type or the comparison."""
) )
def typeRange(self, t): def typeRange(self, t):

@ -26,8 +26,8 @@ class ConstCandidateStateVars(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-constant" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-constant"
WIKI_TITLE = "State variables that could be declared constant" WIKI_TITLE = "State variables that could be declared constant"
WIKI_DESCRIPTION = "Constant state variable should be declared constant to save gas." WIKI_DESCRIPTION = "Constant state variables should be declared constant to save gas."
WIKI_RECOMMENDATION = "Add the `constant` attributes to the state variables that never change." WIKI_RECOMMENDATION = "Add the `constant` attributes to state variables that never change."
@staticmethod @staticmethod
def _valid_candidate(v): def _valid_candidate(v):

@ -30,7 +30,7 @@ contract Uninitialized is Owner{
} }
} }
``` ```
Bob calls `transfer`. As a result, the ethers are sent to the address 0x0 and are lost.""" Bob calls `transfer`. As a result, all Ether is sent to the address `0x0` and is lost."""
WIKI_RECOMMENDATION = "Initialize all the variables. If a variable is meant to be initialized to zero, explicitly set it to zero." WIKI_RECOMMENDATION = "Initialize all the variables. If a variable is meant to be initialized to zero, explicitly set it to zero."

@ -38,7 +38,7 @@ contract Uninitialized{
} }
} }
``` ```
Bob calls `transfer`. As a result, the ethers are sent to the address 0x0 and are lost. Bob calls `transfer`. As a result, the Ether are sent to the address `0x0` and are lost.
""" """
WIKI_RECOMMENDATION = """ WIKI_RECOMMENDATION = """
Initialize all the variables. If a variable is meant to be initialized to zero, explicitly set it to zero. Initialize all the variables. If a variable is meant to be initialized to zero, explicitly set it to zero.

@ -20,7 +20,7 @@ class UninitializedStorageVars(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#uninitialized-storage-variables" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#uninitialized-storage-variables"
WIKI_TITLE = "Uninitialized storage variables" WIKI_TITLE = "Uninitialized storage variables"
WIKI_DESCRIPTION = "An uinitialized storage variable will act as a reference to the first state variable, and can override a critical variable." WIKI_DESCRIPTION = "An uninitialized storage variable will act as a reference to the first state variable, and can override a critical variable."
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
contract Uninitialized{ contract Uninitialized{
@ -36,10 +36,10 @@ contract Uninitialized{
} }
} }
``` ```
Bob calls `func`. As a result, `owner` is override to 0. Bob calls `func`. As a result, `owner` is overridden to `0`.
""" """
WIKI_RECOMMENDATION = "Initialize all the storage variables." WIKI_RECOMMENDATION = "Initialize all storage variables."
# node.context[self.key] contains the uninitialized storage variables # node.context[self.key] contains the uninitialized storage variables
key = "UNINITIALIZEDSTORAGE" key = "UNINITIALIZEDSTORAGE"

@ -21,7 +21,7 @@ class UnusedStateVars(AbstractDetector):
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#unused-state-variables" WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#unused-state-variables"
WIKI_TITLE = "Unused state variables" WIKI_TITLE = "Unused state variable"
WIKI_DESCRIPTION = "Unused state variable." WIKI_DESCRIPTION = "Unused state variable."
WIKI_EXPLOIT_SCENARIO = "" WIKI_EXPLOIT_SCENARIO = ""
WIKI_RECOMMENDATION = "Remove unused state variables." WIKI_RECOMMENDATION = "Remove unused state variables."

@ -41,6 +41,8 @@ class PrinterWrittenVariablesAndAuthorization(AbstractPrinter):
txt = "" txt = ""
all_tables = [] all_tables = []
for contract in self.contracts: for contract in self.contracts:
if contract.is_top_level:
continue
txt += "\nContract %s\n" % contract.name txt += "\nContract %s\n" % contract.name
table = MyPrettyTable( table = MyPrettyTable(
["Function", "State variables written", "Conditions on msg.sender"] ["Function", "State variables written", "Conditions on msg.sender"]

@ -21,6 +21,8 @@ class CFG(AbstractPrinter):
info = "" info = ""
all_files = [] all_files = []
for contract in self.contracts: for contract in self.contracts:
if contract.is_top_level:
continue
for function in contract.functions + contract.modifiers: for function in contract.functions + contract.modifiers:
if original_filename: if original_filename:
filename = "{}-{}-{}.dot".format( filename = "{}-{}-{}.dot".format(

@ -18,6 +18,7 @@ from slither.core.slither_core import SlitherCore
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
from slither.printers.abstract_printer import AbstractPrinter from slither.printers.abstract_printer import AbstractPrinter
from slither.slithir.operations import ( from slither.slithir.operations import (
AccessMember, AccessMember,
Operation, Operation,

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

Loading…
Cancel
Save