Merge branch 'dev' into dev-named-implicit-returns

pull/1880/head
William E Bodell III 2 years ago committed by GitHub
commit 5e051ce6e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .github/scripts/unit_test_runner.sh
  2. 2
      .github/workflows/black.yml
  3. 2
      .github/workflows/linter.yml
  4. 2
      .github/workflows/pip-audit.yml
  5. 2
      .github/workflows/pylint.yml
  6. 2
      .github/workflows/test.yml
  7. 1
      .gitignore
  8. 83
      CONTRIBUTING.md
  9. 88
      Makefile
  10. 8
      examples/flat/a.sol
  11. 13
      examples/flat/b.sol
  12. 10
      scripts/ci_test_flat.sh
  13. 9
      setup.py
  14. 3
      slither/__init__.py
  15. 1
      slither/analyses/data_dependency/data_dependency.py
  16. 15
      slither/core/cfg/node.py
  17. 6
      slither/core/compilation_unit.py
  18. 7
      slither/core/declarations/custom_error.py
  19. 4
      slither/core/declarations/solidity_variables.py
  20. 1
      slither/detectors/all_detectors.py
  21. 4
      slither/detectors/assembly/shift_parameter_mixup.py
  22. 104
      slither/detectors/operations/encode_packed.py
  23. 42
      slither/detectors/operations/unused_return_values.py
  24. 31
      slither/detectors/reentrancy/reentrancy_events.py
  25. 23
      slither/detectors/statements/incorrect_strict_equality.py
  26. 6
      slither/printers/summary/when_not_paused.py
  27. 9
      slither/slithir/convert.py
  28. 2
      slither/slithir/operations/assignment.py
  29. 1
      slither/slithir/operations/binary.py
  30. 5
      slither/slithir/operations/new_array.py
  31. 3
      slither/slithir/operations/new_contract.py
  32. 3
      slither/slithir/operations/new_structure.py
  33. 2
      slither/slithir/operations/unary.py
  34. 3
      slither/solc_parsing/declarations/contract.py
  35. 15
      slither/solc_parsing/declarations/function.py
  36. 3
      slither/solc_parsing/declarations/modifier.py
  37. 2
      slither/tools/flattening/export/export.py
  38. 45
      slither/tools/flattening/flattening.py
  39. 2
      slither/tools/read_storage/read_storage.py
  40. 181
      slither/utils/code_generation.py
  41. 6
      slither/utils/myprettytable.py
  42. 15
      slither/utils/type.py
  43. 7
      slither/visitors/slithir/expression_to_slithir.py
  44. 79
      tests/conftest.py
  45. 13
      tests/e2e/compilation/test_resolution.py
  46. 18
      tests/e2e/detectors/snapshots/detectors__detector_ABIEncoderV2Array_0_4_25_storage_ABIEncoderV2_array_sol__0.txt
  47. 0
      tests/e2e/detectors/snapshots/detectors__detector_ABIEncoderV2Array_0_5_10_storage_ABIEncoderV2_array_sol__0.txt
  48. 18
      tests/e2e/detectors/snapshots/detectors__detector_ABIEncoderV2Array_0_5_9_storage_ABIEncoderV2_array_sol__0.txt
  49. 6
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendErc20NoPermit_0_4_25_arbitrary_send_erc20_sol__0.txt
  50. 6
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendErc20NoPermit_0_5_16_arbitrary_send_erc20_sol__0.txt
  51. 6
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendErc20NoPermit_0_6_11_arbitrary_send_erc20_sol__0.txt
  52. 6
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendErc20NoPermit_0_7_6_arbitrary_send_erc20_sol__0.txt
  53. 2
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendErc20NoPermit_0_8_0_arbitrary_send_erc20_inheritance_sol__0.txt
  54. 6
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendErc20NoPermit_0_8_0_arbitrary_send_erc20_sol__0.txt
  55. 8
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendErc20Permit_0_4_25_arbitrary_send_erc20_permit_sol__0.txt
  56. 8
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendErc20Permit_0_5_16_arbitrary_send_erc20_permit_sol__0.txt
  57. 8
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendErc20Permit_0_6_11_arbitrary_send_erc20_permit_sol__0.txt
  58. 8
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendErc20Permit_0_7_6_arbitrary_send_erc20_permit_sol__0.txt
  59. 8
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendErc20Permit_0_8_0_arbitrary_send_erc20_permit_sol__0.txt
  60. 8
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_4_25_arbitrary_send_eth_sol__0.txt
  61. 8
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_5_16_arbitrary_send_eth_sol__0.txt
  62. 8
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_6_11_arbitrary_send_eth_sol__0.txt
  63. 8
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_7_6_arbitrary_send_eth_sol__0.txt
  64. 12
      tests/e2e/detectors/snapshots/detectors__detector_ArrayByReference_0_4_25_array_by_reference_sol__0.txt
  65. 12
      tests/e2e/detectors/snapshots/detectors__detector_ArrayByReference_0_5_16_array_by_reference_sol__0.txt
  66. 12
      tests/e2e/detectors/snapshots/detectors__detector_ArrayByReference_0_6_11_array_by_reference_sol__0.txt
  67. 12
      tests/e2e/detectors/snapshots/detectors__detector_ArrayByReference_0_7_6_array_by_reference_sol__0.txt
  68. 9
      tests/e2e/detectors/snapshots/detectors__detector_ArrayLengthAssignment_0_4_25_array_length_assignment_sol__0.txt
  69. 9
      tests/e2e/detectors/snapshots/detectors__detector_ArrayLengthAssignment_0_5_16_array_length_assignment_sol__0.txt
  70. 3
      tests/e2e/detectors/snapshots/detectors__detector_Assembly_0_4_25_inline_assembly_contract_sol__0.txt
  71. 6
      tests/e2e/detectors/snapshots/detectors__detector_Assembly_0_4_25_inline_assembly_library_sol__0.txt
  72. 3
      tests/e2e/detectors/snapshots/detectors__detector_Assembly_0_5_16_inline_assembly_contract_sol__0.txt
  73. 6
      tests/e2e/detectors/snapshots/detectors__detector_Assembly_0_5_16_inline_assembly_library_sol__0.txt
  74. 3
      tests/e2e/detectors/snapshots/detectors__detector_Assembly_0_6_11_inline_assembly_contract_sol__0.txt
  75. 6
      tests/e2e/detectors/snapshots/detectors__detector_Assembly_0_6_11_inline_assembly_library_sol__0.txt
  76. 3
      tests/e2e/detectors/snapshots/detectors__detector_Assembly_0_7_6_inline_assembly_contract_sol__0.txt
  77. 6
      tests/e2e/detectors/snapshots/detectors__detector_Assembly_0_7_6_inline_assembly_library_sol__0.txt
  78. 12
      tests/e2e/detectors/snapshots/detectors__detector_AssertStateChange_0_4_25_assert_state_change_sol__0.txt
  79. 12
      tests/e2e/detectors/snapshots/detectors__detector_AssertStateChange_0_5_16_assert_state_change_sol__0.txt
  80. 12
      tests/e2e/detectors/snapshots/detectors__detector_AssertStateChange_0_6_11_assert_state_change_sol__0.txt
  81. 12
      tests/e2e/detectors/snapshots/detectors__detector_AssertStateChange_0_7_6_assert_state_change_sol__0.txt
  82. 2
      tests/e2e/detectors/snapshots/detectors__detector_Backdoor_0_4_25_backdoor_sol__0.txt
  83. 2
      tests/e2e/detectors/snapshots/detectors__detector_Backdoor_0_5_16_backdoor_sol__0.txt
  84. 2
      tests/e2e/detectors/snapshots/detectors__detector_Backdoor_0_6_11_backdoor_sol__0.txt
  85. 2
      tests/e2e/detectors/snapshots/detectors__detector_Backdoor_0_7_6_backdoor_sol__0.txt
  86. 8
      tests/e2e/detectors/snapshots/detectors__detector_BadPRNG_0_4_25_bad_prng_sol__0.txt
  87. 8
      tests/e2e/detectors/snapshots/detectors__detector_BadPRNG_0_5_16_bad_prng_sol__0.txt
  88. 8
      tests/e2e/detectors/snapshots/detectors__detector_BadPRNG_0_6_11_bad_prng_sol__0.txt
  89. 8
      tests/e2e/detectors/snapshots/detectors__detector_BadPRNG_0_7_6_bad_prng_sol__0.txt
  90. 3
      tests/e2e/detectors/snapshots/detectors__detector_BooleanConstantMisuse_0_4_25_boolean_constant_misuse_sol__0.txt
  91. 3
      tests/e2e/detectors/snapshots/detectors__detector_BooleanConstantMisuse_0_5_16_boolean_constant_misuse_sol__0.txt
  92. 3
      tests/e2e/detectors/snapshots/detectors__detector_BooleanConstantMisuse_0_6_11_boolean_constant_misuse_sol__0.txt
  93. 3
      tests/e2e/detectors/snapshots/detectors__detector_BooleanConstantMisuse_0_7_6_boolean_constant_misuse_sol__0.txt
  94. 3
      tests/e2e/detectors/snapshots/detectors__detector_BooleanEquality_0_4_25_boolean_constant_equality_sol__0.txt
  95. 3
      tests/e2e/detectors/snapshots/detectors__detector_BooleanEquality_0_5_16_boolean_constant_equality_sol__0.txt
  96. 3
      tests/e2e/detectors/snapshots/detectors__detector_BooleanEquality_0_6_11_boolean_constant_equality_sol__0.txt
  97. 3
      tests/e2e/detectors/snapshots/detectors__detector_BooleanEquality_0_7_6_boolean_constant_equality_sol__0.txt
  98. 26
      tests/e2e/detectors/snapshots/detectors__detector_BuiltinSymbolShadowing_0_4_25_shadowing_builtin_symbols_sol__0.txt
  99. 24
      tests/e2e/detectors/snapshots/detectors__detector_BuiltinSymbolShadowing_0_5_16_shadowing_builtin_symbols_sol__0.txt
  100. 2
      tests/e2e/detectors/snapshots/detectors__detector_ConstantFunctionsAsm_0_4_25_constant_sol__0.txt
  101. Some files were not shown because too many files have changed in this diff Show More

@ -2,11 +2,11 @@
# used to pass --cov=$path and --cov-append to pytest # used to pass --cov=$path and --cov-append to pytest
if [ "$1" != "" ]; then if [ "$1" != "" ]; then
pytest "$1" tests/unit/ pytest "$1" tests/unit/ -n auto
status_code=$? status_code=$?
python -m coverage report python -m coverage report
else else
pytest tests/unit/ pytest tests/unit/ -n auto
status_code=$? status_code=$?
fi fi

@ -42,7 +42,7 @@ jobs:
cp pyproject.toml .github/linters cp pyproject.toml .github/linters
- name: Black - name: Black
uses: github/super-linter/slim@v4.9.2 uses: super-linter/super-linter/slim@v4.9.2
if: always() if: always()
env: env:
# run linter on everything to catch preexisting problems # run linter on everything to catch preexisting problems

@ -43,7 +43,7 @@ jobs:
cp pyproject.toml .github/linters cp pyproject.toml .github/linters
- name: Lint everything else - name: Lint everything else
uses: github/super-linter/slim@v4.9.2 uses: super-linter/super-linter/slim@v4.9.2
if: always() if: always()
env: env:
# run linter on everything to catch preexisting problems # run linter on everything to catch preexisting problems

@ -34,6 +34,6 @@ jobs:
python -m pip install . python -m pip install .
- name: Run pip-audit - name: Run pip-audit
uses: trailofbits/gh-action-pip-audit@v0.0.4 uses: pypa/gh-action-pip-audit@v1.0.7
with: with:
virtual-environment: /tmp/pip-audit-env virtual-environment: /tmp/pip-audit-env

@ -37,7 +37,7 @@ jobs:
cp pyproject.toml .github/linters cp pyproject.toml .github/linters
- name: Pylint - name: Pylint
uses: github/super-linter/slim@v4.9.2 uses: super-linter/super-linter/slim@v4.9.2
if: always() if: always()
env: env:
# Run linters only on new files for pylint to speed up the CI # Run linters only on new files for pylint to speed up the CI

@ -37,8 +37,6 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
pip install ".[test]" pip install ".[test]"
solc-select install 0.8.0
solc-select use 0.8.0
- name: Setup node - name: Setup node
uses: actions/setup-node@v3 uses: actions/setup-node@v3

1
.gitignore vendored

@ -42,6 +42,7 @@ htmlcov/
.coverage .coverage
.coverage.* .coverage.*
.cache .cache
.pytest_cache
nosetests.xml nosetests.xml
coverage.xml coverage.xml
*.cover *.cover

@ -1,15 +1,19 @@
# Contributing to Slither # Contributing to Slither
First, thanks for your interest in contributing to Slither! We welcome and appreciate all contributions, including bug reports, feature suggestions, tutorials/blog posts, and code improvements. First, thanks for your interest in contributing to Slither! We welcome and appreciate all contributions, including bug reports, feature suggestions, tutorials/blog posts, and code improvements.
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 "Discussions" page, and you may also join 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:
@ -23,6 +27,7 @@ Some pull request guidelines:
## Directory Structure ## Directory Structure
Below is a rough outline of slither's design: Below is a rough outline of slither's design:
```text ```text
. .
├── analyses # Provides additional info such as data dependency ├── analyses # Provides additional info such as data dependency
@ -39,9 +44,10 @@ Below is a rough outline of slither's design:
A code walkthrough is available [here](https://www.youtube.com/watch?v=EUl3UlYSluU). A code walkthrough is available [here](https://www.youtube.com/watch?v=EUl3UlYSluU).
## 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).
To run the unit tests, you need to clone this repository and run `pip install ".[dev]"`. To run the unit tests, you need to clone this repository and run `make test`. Run a specific test with `make test TESTS=$test_name`. The names of tests can be obtained with `pytest tests --collect-only`.
### Linters ### Linters
@ -49,40 +55,63 @@ Several linters and security checkers are run on the PRs.
To run them locally in the root dir of the repository: To run them locally in the root dir of the repository:
- `pylint slither tests --rcfile pyproject.toml` - `make lint`
- `black . --config pyproject.toml`
> Note, this only validates but does not modify the code.
To automatically reformat the code:
- `make reformat`
We use pylint `2.13.4`, black `22.3.0`. We use pylint `2.13.4`, black `22.3.0`.
### Detectors tests ### Testing
Slither's test suite is divided into three categories end-to-end (`tests/e2e`), unit (`tests/unit`), and tools (`tests/tools/`).
How do I know what kind of test(s) to write?
- End-to-end: functionality that requires invoking `Slither` and inspecting some output such as printers and detectors.
- Unit: additions and modifications to objects should be accompanied by a unit test that defines the expected behavior. Aim to write functions in as pure a way as possible such that they are easier to test.
- Tools: tools built on top of Slither (`slither/tools`) but not apart of its core functionality
#### Adding detector tests
For each new detector, at least one regression tests must be present. For each new detector, at least one regression tests must be present.
- Create a test in `tests` 1. Create a folder in `tests/e2e/detectors/test_data` with the detector's argument name.
- Update `ALL_TEST` in `tests/test_detectors.py` 2. Create a test contract in `tests/e2e/detectors/test_data/<detector_name>/`.
- Run `python ./tests/test_detectors.py --generate`. This will generate the json artifacts in `tests/expected_json`. Add the generated files to git. 3. Update `ALL_TEST` in `tests/e2e/detectors/test_detectors.py`
- If updating an existing detector, identify the respective json artifacts and then delete them, or run `python ./tests/test_detectors.py --overwrite` instead. 4. Run `python tests/e2e/detectors/test_detectors.py --compile` to create a zip file of the compilation artifacts.
- Run `pytest ./tests/test_detectors.py` and check that everything worked. 5. `pytest tests/e2e/detectors/test_detectors.py --insta update-new`. This will generate a snapshot of the detector output in `tests/e2e/detectors/snapshots/`. If updating an existing detector, run `pytest tests/e2e/detectors/test_detectors.py --insta review` and accept or reject the updates.
6. Run `pytest tests/e2e/detectors/test_detectors.py` to ensure everything worked. Then, add and commit the files to git.
To see the tests coverage, run `pytest tests/test_detectors.py --cov=slither/detectors --cov-branch --cov-report html`.
To run tests for a specific detector, run `pytest tests/test_detectors.py -k ReentrancyReadBeforeWritten` (the detector's class name is the argument). > ##### Helpful commands for detector tests
To run tests for a specific version, run `pytest tests/test_detectors.py -k 0.7.6`. >
The IDs of tests can be inspected using `pytest tests/test_detectors.py --collect-only`. > - To see the tests coverage, run `pytest tests/e2e/detectors/test_detectors.py --cov=slither/detectors --cov-branch --cov-report html`.
> - To run tests for a specific detector, run `pytest tests/e2e/detectors/test_detectors.py -k ReentrancyReadBeforeWritten`(the detector's class name is the argument).
### Parser tests > - To run tests for a specific version, run `pytest tests/e2e/detectors/test_detectors.py -k 0.7.6`.
- Create a test in `tests/ast-parsing` > - The IDs of tests can be inspected using `pytest tests/e2e/detectors/test_detectors.py --collect-only`.
- Run `python ./tests/test_ast_parsing.py --compile`. This will compile the artifact in `tests/ast-parsing/compile`. Add the compiled artifact to git.
- Run `python ./tests/test_ast_parsing.py --generate`. This will generate the json artifacts in `tests/ast-parsing/expected_json`. Add the generated files to git. #### Adding parsing tests
- Run `pytest ./tests/test_ast_parsing.py` and check that everything worked.
1. Create a test in `tests/e2e/solc_parsing/`
To see the tests coverage, run `pytest tests/test_ast_parsing.py --cov=slither/solc_parsing --cov-branch --cov-report html` 2. Run `python tests/e2e/solc_parsing/test_ast_parsing.py --compile`. This will compile the artifact in `tests/e2e/solc_parsing/compile`. Add the compiled artifact to git.
To run tests for a specific test case, run `pytest tests/test_ast_parsing.py -k user_defined_value_type` (the filename is the argument). 3. Run `python tests/e2e/solc_parsing/test_ast_parsing.py --generate`. This will generate the json artifacts in `tests/e2e/solc_parsing/expected_json`. Add the generated files to git.
To run tests for a specific version, run `pytest tests/test_ast_parsing.py -k 0.8.12`. 4. Run `pytest tests/e2e/solc_parsing/test_ast_parsing.py` and check that everything worked.
To run tests for a specific compiler json format, run `pytest tests/test_ast_parsing.py -k legacy` (can be legacy or compact).
The IDs of tests can be inspected using ``pytest tests/test_ast_parsing.py --collect-only`. > ##### Helpful commands for parsing tests
>
> - To see the tests coverage, run `pytest tests/e2e/solc_parsing/test_ast_parsing.py --cov=slither/solc_parsing --cov-branch --cov-report html`
> - To run tests for a specific test case, run `pytest tests/e2e/solc_parsing/test_ast_parsing.py -k user_defined_value_type` (the filename is the argument).
> - To run tests for a specific version, run `pytest tests/e2e/solc_parsing/test_ast_parsing.py -k 0.8.12`.
> - To run tests for a specific compiler json format, run `pytest tests/e2e/solc_parsing/test_ast_parsing.py -k legacy` (can be legacy or compact).
> - The IDs of tests can be inspected using ``pytest tests/e2e/solc_parsing/test_ast_parsing.py --collect-only`.
### Synchronization with crytic-compile ### Synchronization with crytic-compile
By default, `slither` follows either the latest version of crytic-compile in pip, or `crytic-compile@master` (look for dependencies in [`setup.py`](./setup.py). If crytic-compile development comes with breaking changes, the process to update `slither` is: By default, `slither` follows either the latest version of crytic-compile in pip, or `crytic-compile@master` (look for dependencies in [`setup.py`](./setup.py). If crytic-compile development comes with breaking changes, the process to update `slither` is:
- Update `slither/setup.py` to point to the related crytic-compile's branch - Update `slither/setup.py` to point to the related crytic-compile's branch
- Create a PR in `slither` and ensure it passes the CI - Create a PR in `slither` and ensure it passes the CI
- Once the development branch is merged in `crytic-compile@master`, ensure `slither` follows the `master` branch - Once the development branch is merged in `crytic-compile@master`, ensure `slither` follows the `master` branch

@ -0,0 +1,88 @@
SHELL := /bin/bash
PY_MODULE := slither
TEST_MODULE := tests
ALL_PY_SRCS := $(shell find $(PY_MODULE) -name '*.py') \
$(shell find test -name '*.py')
# Optionally overriden by the user, if they're using a virtual environment manager.
VENV ?= env
# On Windows, venv scripts/shims are under `Scripts` instead of `bin`.
VENV_BIN := $(VENV)/bin
ifeq ($(OS),Windows_NT)
VENV_BIN := $(VENV)/Scripts
endif
# Optionally overridden by the user in the `release` target.
BUMP_ARGS :=
# Optionally overridden by the user in the `test` target.
TESTS :=
# Optionally overridden by the user/CI, to limit the installation to a specific
# subset of development dependencies.
SLITHER_EXTRA := dev
# If the user selects a specific test pattern to run, set `pytest` to fail fast
# and only run tests that match the pattern.
# Otherwise, run all tests and enable coverage assertions, since we expect
# complete test coverage.
ifneq ($(TESTS),)
TEST_ARGS := -x -k $(TESTS)
COV_ARGS :=
else
TEST_ARGS := -n auto
COV_ARGS := # --fail-under 100
endif
.PHONY: all
all:
@echo "Run my targets individually!"
.PHONY: dev
dev: $(VENV)/pyvenv.cfg
.PHONY: run
run: $(VENV)/pyvenv.cfg
@. $(VENV_BIN)/activate && slither $(ARGS)
$(VENV)/pyvenv.cfg: pyproject.toml
# Create our Python 3 virtual environment
python3 -m venv env
$(VENV_BIN)/python -m pip install --upgrade pip
$(VENV_BIN)/python -m pip install -e .[$(SLITHER_EXTRA)]
.PHONY: lint
lint: $(VENV)/pyvenv.cfg
. $(VENV_BIN)/activate && \
black --check . && \
pylint $(PY_MODULE) $(TEST_MODULE)
# ruff $(ALL_PY_SRCS) && \
# mypy $(PY_MODULE) &&
.PHONY: reformat
reformat:
. $(VENV_BIN)/activate && \
black .
.PHONY: test tests
test tests: $(VENV)/pyvenv.cfg
. $(VENV_BIN)/activate && \
pytest --cov=$(PY_MODULE) $(T) $(TEST_ARGS) && \
python -m coverage report -m $(COV_ARGS)
.PHONY: doc
doc: $(VENV)/pyvenv.cfg
. $(VENV_BIN)/activate && \
PDOC_ALLOW_EXEC=1 pdoc -o html slither '!slither.tools'
.PHONY: package
package: $(VENV)/pyvenv.cfg
. $(VENV_BIN)/activate && \
python3 -m build
.PHONY: edit
edit:
$(EDITOR) $(ALL_PY_SRCS)

@ -1,3 +1,9 @@
contract A{ pragma solidity 0.8.19;
error RevertIt();
contract Example {
function reverts() external pure {
revert RevertIt();
}
} }

@ -1,5 +1,16 @@
import "./a.sol"; import "./a.sol";
contract B is A{ pragma solidity 0.8.19;
enum B {
a,
b
}
contract T {
Example e = new Example();
function b() public returns(uint) {
B b = B.a;
return 4;
}
} }

@ -1,6 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
shopt -s extglob
### Test slither-prop ### Test slither-flat
solc-select use 0.8.19 --always-install
cd examples/flat || exit 1 cd examples/flat || exit 1
@ -9,4 +11,10 @@ if ! slither-flat b.sol; then
exit 1 exit 1
fi fi
SUFFIX="@(sol)"
if ! solc "crytic-export/flattening/"*$SUFFIX; then
echo "solc failed on flattened files"
exit 1
fi
exit 0 exit 0

@ -13,10 +13,10 @@ setup(
python_requires=">=3.8", python_requires=">=3.8",
install_requires=[ install_requires=[
"packaging", "packaging",
"prettytable>=0.7.2", "prettytable>=3.3.0",
"pycryptodome>=3.4.6", "pycryptodome>=3.4.6",
"crytic-compile>=0.3.1,<0.4.0", # "crytic-compile>=0.3.1,<0.4.0",
# "crytic-compile@git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile", "crytic-compile@git+https://github.com/crytic/crytic-compile.git@windows-rel-path#egg=crytic-compile",
"web3>=6.0.0", "web3>=6.0.0",
], ],
extras_require={ extras_require={
@ -31,6 +31,9 @@ setup(
"deepdiff", "deepdiff",
"numpy", "numpy",
"coverage[toml]", "coverage[toml]",
"filelock",
"pytest-insta",
"solc-select@git+https://github.com/crytic/solc-select.git@query-artifact-path#egg=solc-select",
], ],
"doc": [ "doc": [
"pdoc", "pdoc",

@ -1 +1,4 @@
"""
.. include:: ../README.md
"""
from .slither import Slither from .slither import Slither

@ -129,6 +129,7 @@ GENERIC_TAINT = {
SolidityVariableComposed("msg.value"), SolidityVariableComposed("msg.value"),
SolidityVariableComposed("msg.data"), SolidityVariableComposed("msg.data"),
SolidityVariableComposed("tx.origin"), SolidityVariableComposed("tx.origin"),
SolidityVariableComposed("tx.gasprice"),
} }

@ -620,6 +620,21 @@ class Node(SourceMapping): # pylint: disable=too-many-public-methods
""" """
self._sons.append(son) self._sons.append(son)
def replace_son(self, ori_son: "Node", new_son: "Node") -> None:
"""Replace a son node. Do nothing if the node to replace is not a son
Args:
ori_son: son to replace
new_son: son to replace with
"""
for i, s in enumerate(self._sons):
if s.node_id == ori_son.node_id:
idx = i
break
else:
return
self._sons[idx] = new_son
def set_sons(self, sons: List["Node"]) -> None: def set_sons(self, sons: List["Node"]) -> None:
"""Set the son nodes """Set the son nodes

@ -13,7 +13,7 @@ from slither.core.declarations import (
Function, Function,
Modifier, Modifier,
) )
from slither.core.declarations.custom_error import CustomError from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel
from slither.core.declarations.enum_top_level import EnumTopLevel from slither.core.declarations.enum_top_level import EnumTopLevel
from slither.core.declarations.function_top_level import FunctionTopLevel from slither.core.declarations.function_top_level import FunctionTopLevel
from slither.core.declarations.structure_top_level import StructureTopLevel from slither.core.declarations.structure_top_level import StructureTopLevel
@ -46,7 +46,7 @@ class SlitherCompilationUnit(Context):
self._using_for_top_level: List[UsingForTopLevel] = [] self._using_for_top_level: List[UsingForTopLevel] = []
self._pragma_directives: List[Pragma] = [] self._pragma_directives: List[Pragma] = []
self._import_directives: List[Import] = [] self._import_directives: List[Import] = []
self._custom_errors: List[CustomError] = [] self._custom_errors: List[CustomErrorTopLevel] = []
self._user_defined_value_types: Dict[str, TypeAliasTopLevel] = {} self._user_defined_value_types: Dict[str, TypeAliasTopLevel] = {}
self._all_functions: Set[Function] = set() self._all_functions: Set[Function] = set()
@ -216,7 +216,7 @@ class SlitherCompilationUnit(Context):
return self._using_for_top_level return self._using_for_top_level
@property @property
def custom_errors(self) -> List[CustomError]: def custom_errors(self) -> List[CustomErrorTopLevel]:
return self._custom_errors return self._custom_errors
@property @property

@ -1,8 +1,8 @@
from typing import List, TYPE_CHECKING, Optional, Type from typing import List, TYPE_CHECKING, Optional, Type
from slither.core.solidity_types import UserDefinedType
from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.variables.local_variable import LocalVariable from slither.core.variables.local_variable import LocalVariable
from slither.utils.type import is_underlying_type_address
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.compilation_unit import SlitherCompilationUnit
@ -43,10 +43,7 @@ class CustomError(SourceMapping):
@staticmethod @staticmethod
def _convert_type_for_solidity_signature(t: Optional[Type]) -> str: def _convert_type_for_solidity_signature(t: Optional[Type]) -> str:
# pylint: disable=import-outside-toplevel if is_underlying_type_address(t):
from slither.core.declarations import Contract
if isinstance(t, UserDefinedType) and isinstance(t.type, Contract):
return "address" return "address"
return str(t) return str(t)

@ -201,6 +201,10 @@ class SolidityCustomRevert(SolidityFunction):
self._custom_error = custom_error self._custom_error = custom_error
self._return_type: List[Union[TypeInformation, ElementaryType]] = [] self._return_type: List[Union[TypeInformation, ElementaryType]] = []
@property
def custom_error(self) -> CustomError:
return self._custom_error
def __eq__(self, other: Any) -> bool: def __eq__(self, other: Any) -> bool:
return ( return (
self.__class__ == other.__class__ self.__class__ == other.__class__

@ -89,3 +89,4 @@ from .functions.protected_variable import ProtectedVariables
from .functions.permit_domain_signature_collision import DomainSeparatorCollision from .functions.permit_domain_signature_collision import DomainSeparatorCollision
from .functions.codex import Codex from .functions.codex import Codex
from .functions.cyclomatic_complexity import CyclomaticComplexity from .functions.cyclomatic_complexity import CyclomaticComplexity
from .operations.encode_packed import EncodePackedCollision

@ -52,7 +52,9 @@ The shift statement will right-shift the constant 8 by `a` bits"""
BinaryType.LEFT_SHIFT, BinaryType.LEFT_SHIFT,
BinaryType.RIGHT_SHIFT, BinaryType.RIGHT_SHIFT,
]: ]:
if isinstance(ir.variable_left, Constant): if isinstance(ir.variable_left, Constant) and not isinstance(
ir.variable_right, Constant
):
info: DETECTOR_INFO = [ info: DETECTOR_INFO = [
f, f,
" contains an incorrect shift operation: ", " contains an incorrect shift operation: ",

@ -0,0 +1,104 @@
"""
Module detecting usage of more than one dynamic type in abi.encodePacked() arguments which could lead to collision
"""
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.solidity_variables import SolidityFunction
from slither.slithir.operations import SolidityCall
from slither.analyses.data_dependency.data_dependency import is_tainted
from slither.core.solidity_types import ElementaryType
from slither.core.solidity_types import ArrayType
def _is_dynamic_type(arg):
"""
Args:
arg (function argument)
Returns:
Bool
"""
if isinstance(arg.type, ElementaryType) and (arg.type.name in ["string", "bytes"]):
return True
if isinstance(arg.type, ArrayType) and arg.type.length is None:
return True
return False
def _detect_abi_encodePacked_collision(contract):
"""
Args:
contract (Contract)
Returns:
list((Function), (list (Node)))
"""
ret = []
# pylint: disable=too-many-nested-blocks
for f in contract.functions_and_modifiers_declared:
for n in f.nodes:
for ir in n.irs:
if isinstance(ir, SolidityCall) and ir.function == SolidityFunction(
"abi.encodePacked()"
):
dynamic_type_count = 0
for arg in ir.arguments:
if is_tainted(arg, contract) and _is_dynamic_type(arg):
dynamic_type_count += 1
elif dynamic_type_count > 1:
ret.append((f, n))
dynamic_type_count = 0
else:
dynamic_type_count = 0
if dynamic_type_count > 1:
ret.append((f, n))
return ret
class EncodePackedCollision(AbstractDetector):
"""
Detect usage of more than one dynamic type in abi.encodePacked() arguments which could to collision
"""
ARGUMENT = "encode-packed-collision"
HELP = "ABI encodePacked Collision"
IMPACT = DetectorClassification.HIGH
CONFIDENCE = DetectorClassification.HIGH
WIKI = (
"https://github.com/crytic/slither/wiki/Detector-Documentation#abi-encodePacked-collision"
)
WIKI_TITLE = "ABI encodePacked Collision"
WIKI_DESCRIPTION = """Detect collision due to dynamic type usages in `abi.encodePacked`"""
WIKI_EXPLOIT_SCENARIO = """
```solidity
contract Sign {
function get_hash_for_signature(string name, string doc) external returns(bytes32) {
return keccak256(abi.encodePacked(name, doc));
}
}
```
Bob calls `get_hash_for_signature` with (`bob`, `This is the content`). The hash returned is used as an ID.
Eve creates a collision with the ID using (`bo`, `bThis is the content`) and compromises the system.
"""
WIKI_RECOMMENDATION = """Do not use more than one dynamic type in `abi.encodePacked()`
(see the [Solidity documentation](https://solidity.readthedocs.io/en/v0.5.10/abi-spec.html?highlight=abi.encodePacked#non-standard-packed-modeDynamic)).
Use `abi.encode()`, preferably."""
def _detect(self):
"""Detect usage of more than one dynamic type in abi.encodePacked(..) arguments which could lead to collision"""
results = []
for c in self.compilation_unit.contracts:
values = _detect_abi_encodePacked_collision(c)
for func, node in values:
info = [
func,
" calls abi.encodePacked() with multiple dynamic arguments:\n\t- ",
node,
"\n",
]
json = self.generate_result(info)
results.append(json)
return results

@ -3,7 +3,7 @@ Module detecting unused return values from external calls
""" """
from typing import List from typing import List
from slither.core.cfg.node import Node from slither.core.cfg.node import Node, NodeType
from slither.core.declarations import Function from slither.core.declarations import Function
from slither.core.declarations.function_contract import FunctionContract from slither.core.declarations.function_contract import FunctionContract
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
@ -12,8 +12,8 @@ from slither.detectors.abstract_detector import (
DetectorClassification, DetectorClassification,
DETECTOR_INFO, DETECTOR_INFO,
) )
from slither.slithir.operations import HighLevelCall from slither.slithir.operations import HighLevelCall, Assignment, Unpack, Operation
from slither.slithir.operations.operation import Operation from slither.slithir.variables import TupleVariable
from slither.utils.output import Output from slither.utils.output import Output
@ -50,13 +50,18 @@ contract MyConc{
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."
def _is_instance(self, ir: Operation) -> bool: # pylint: disable=no-self-use def _is_instance(self, ir: Operation) -> bool: # pylint: disable=no-self-use
return isinstance(ir, HighLevelCall) and ( return (
( isinstance(ir, HighLevelCall)
isinstance(ir.function, Function) and (
and ir.function.solidity_signature (
not in ["transfer(address,uint256)", "transferFrom(address,address,uint256)"] isinstance(ir.function, Function)
and ir.function.solidity_signature
not in ["transfer(address,uint256)", "transferFrom(address,address,uint256)"]
)
or not isinstance(ir.function, Function)
) )
or not isinstance(ir.function, Function) or ir.node.type == NodeType.TRY
and isinstance(ir, (Assignment, Unpack))
) )
def detect_unused_return_values( def detect_unused_return_values(
@ -71,18 +76,27 @@ contract MyConc{
""" """
values_returned = [] values_returned = []
nodes_origin = {} nodes_origin = {}
# pylint: disable=too-many-nested-blocks
for n in f.nodes: for n in f.nodes:
for ir in n.irs: for ir in n.irs:
if self._is_instance(ir): if self._is_instance(ir):
# if a return value is stored in a state variable, it's ok # if a return value is stored in a state variable, it's ok
if ir.lvalue and not isinstance(ir.lvalue, StateVariable): if ir.lvalue and not isinstance(ir.lvalue, StateVariable):
values_returned.append(ir.lvalue) values_returned.append((ir.lvalue, None))
nodes_origin[ir.lvalue] = ir nodes_origin[ir.lvalue] = ir
if isinstance(ir.lvalue, TupleVariable):
# we iterate the number of elements the tuple has
# and add a (variable, index) in values_returned for each of them
for index in range(len(ir.lvalue.type)):
values_returned.append((ir.lvalue, index))
for read in ir.read: for read in ir.read:
if read in values_returned: remove = (read, ir.index) if isinstance(ir, Unpack) else (read, None)
values_returned.remove(read) if remove in values_returned:
# this is needed to remove the tuple variable when the first time one of its element is used
return [nodes_origin[value].node for value in values_returned] if remove[1] is not None and (remove[0], None) in values_returned:
values_returned.remove((remove[0], None))
values_returned.remove(remove)
return [nodes_origin[value].node for (value, _) in values_returned]
def _detect(self) -> List[Output]: def _detect(self) -> List[Output]:
"""Detect high level calls which return a value that are never used""" """Detect high level calls which return a value that are never used"""

@ -29,24 +29,45 @@ class ReentrancyEvent(Reentrancy):
# region wiki_description # region wiki_description
WIKI_DESCRIPTION = """ WIKI_DESCRIPTION = """
Detection of the [reentrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy). Detects [reentrancies](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy) that allow manipulation of the order or value of events."""
Only report reentrancies leading to out-of-order events."""
# endregion wiki_description # endregion wiki_description
# region wiki_exploit_scenario # region wiki_exploit_scenario
WIKI_EXPLOIT_SCENARIO = """ WIKI_EXPLOIT_SCENARIO = """
```solidity ```solidity
function bug(Called d){ contract ReentrantContract {
function f() external {
if (BugReentrancyEvents(msg.sender).counter() == 1) {
BugReentrancyEvents(msg.sender).count(this);
}
}
}
contract Counter {
uint public counter;
event Counter(uint);
}
contract BugReentrancyEvents is Counter {
function count(ReentrantContract d) external {
counter += 1; counter += 1;
d.f(); d.f();
emit Counter(counter); emit Counter(counter);
} }
}
contract NoReentrancyEvents is Counter {
function count(ReentrantContract d) external {
counter += 1;
emit Counter(counter);
d.f();
}
}
``` ```
If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, which might lead to issues for third parties.""" If the external call `d.f()` re-enters `BugReentrancyEvents`, the `Counter` events will be incorrect (`Counter(2)`, `Counter(2)`) whereas `NoReentrancyEvents` will correctly emit
(`Counter(1)`, `Counter(2)`). This may cause issues for offchain components that rely on the values of events e.g. checking for the amount deposited to a bridge."""
# endregion wiki_exploit_scenario # endregion wiki_exploit_scenario
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](https://docs.soliditylang.org/en/latest/security-considerations.html#re-entrancy)."
STANDARD_JSON = False STANDARD_JSON = False

@ -31,6 +31,7 @@ from slither.slithir.variables.constant import Constant
from slither.slithir.variables.local_variable import LocalIRVariable from slither.slithir.variables.local_variable import LocalIRVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from slither.utils.output import Output from slither.utils.output import Output
from slither.utils.type import is_underlying_type_address
class IncorrectStrictEquality(AbstractDetector): class IncorrectStrictEquality(AbstractDetector):
@ -72,6 +73,19 @@ contract Crowdsale{
def is_direct_comparison(ir: Operation) -> bool: def is_direct_comparison(ir: Operation) -> bool:
return isinstance(ir, Binary) and ir.type == BinaryType.EQUAL return isinstance(ir, Binary) and ir.type == BinaryType.EQUAL
@staticmethod
def is_not_comparing_addresses(ir: Binary) -> bool:
"""
Comparing addresses strictly should not be flagged.
"""
if is_underlying_type_address(ir.variable_left.type) and is_underlying_type_address(
ir.variable_right.type
):
return False
return True
@staticmethod @staticmethod
def is_any_tainted( def is_any_tainted(
variables: List[ variables: List[
@ -108,7 +122,6 @@ contract Crowdsale{
): ):
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)"
@ -125,7 +138,6 @@ contract Crowdsale{
if isinstance(ir, Assignment): if isinstance(ir, Assignment):
if ir.rvalue in self.sources_taint: if ir.rvalue in self.sources_taint:
taints.append(ir.lvalue) taints.append(ir.lvalue)
return taints return taints
# Retrieve all tainted (node, function) pairs # Retrieve all tainted (node, function) pairs
@ -145,7 +157,12 @@ contract Crowdsale{
for ir in node.irs_ssa: for ir in node.irs_ssa:
# Filter to only tainted equality (==) comparisons # Filter to only tainted equality (==) comparisons
if self.is_direct_comparison(ir) and self.is_any_tainted(ir.used, taints, func): if (
self.is_direct_comparison(ir)
# Filter out address comparisons which may occur due to lack of field sensitivity in data dependency
and self.is_not_comparing_addresses(ir)
and self.is_any_tainted(ir.used, taints, func)
):
if func not in results: if func not in results:
results[func] = [] results[func] = []
results[func].append(node) results[func].append(node)

@ -10,8 +10,6 @@ from slither.utils.myprettytable import MyPrettyTable
def _use_modifier(function: Function, modifier_name: str = "whenNotPaused") -> bool: def _use_modifier(function: Function, modifier_name: str = "whenNotPaused") -> bool:
if function.is_constructor or function.view or function.pure:
return False
for internal_call in function.all_internal_calls(): for internal_call in function.all_internal_calls():
if isinstance(internal_call, SolidityFunction): if isinstance(internal_call, SolidityFunction):
@ -23,7 +21,7 @@ def _use_modifier(function: Function, modifier_name: str = "whenNotPaused") -> b
class PrinterWhenNotPaused(AbstractPrinter): class PrinterWhenNotPaused(AbstractPrinter):
ARGUMENT = "pausable" ARGUMENT = "not-pausable"
HELP = "Print functions that do not use whenNotPaused" HELP = "Print functions that do not use whenNotPaused"
WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#when-not-paused" WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#when-not-paused"
@ -46,6 +44,8 @@ class PrinterWhenNotPaused(AbstractPrinter):
table = MyPrettyTable(["Name", "Use whenNotPaused"]) table = MyPrettyTable(["Name", "Use whenNotPaused"])
for function in contract.functions_entry_points: for function in contract.functions_entry_points:
if function.is_constructor or function.view or function.pure:
continue
status = "X" if _use_modifier(function, modifier_name) else "" status = "X" if _use_modifier(function, modifier_name) else ""
table.add_row([function.solidity_signature, status]) table.add_row([function.solidity_signature, status])

@ -1363,7 +1363,14 @@ def convert_to_pop(ir: HighLevelCall, node: "Node") -> List[Operation]:
# TODO the following is equivalent to length.points_to = arr # TODO the following is equivalent to length.points_to = arr
# Should it be removed? # Should it be removed?
ir_length.lvalue.points_to = arr ir_length.lvalue.points_to = arr
element_to_delete.set_type(ElementaryType("uint256")) # Note bytes is an ElementaryType not ArrayType so in that case we use ir.destination.type
# while in other cases such as uint256[] (ArrayType) we use ir.destination.type.type
# in this way we will have the type always set to the corresponding ElementaryType
element_to_delete.set_type(
ir.destination.type
if isinstance(ir.destination.type, ElementaryType)
else ir.destination.type.type
)
ir_assign_element_to_delete.set_expression(ir.expression) ir_assign_element_to_delete.set_expression(ir.expression)
ir_assign_element_to_delete.set_node(ir.node) ir_assign_element_to_delete.set_node(ir.node)
ret.append(ir_assign_element_to_delete) ret.append(ir_assign_element_to_delete)

@ -50,5 +50,5 @@ class Assignment(OperationWithLValue):
points = lvalue.points_to points = lvalue.points_to
while isinstance(points, ReferenceVariable): while isinstance(points, ReferenceVariable):
points = points.points_to points = points.points_to
return f"{lvalue} (->{points}) := {self.rvalue}({self.rvalue.type})" return f"{lvalue}({lvalue.type}) (->{points}) := {self.rvalue}({self.rvalue.type})"
return f"{lvalue}({lvalue.type}) := {self.rvalue}({self.rvalue.type})" return f"{lvalue}({lvalue.type}) := {self.rvalue}({self.rvalue.type})"

@ -94,7 +94,6 @@ class BinaryType(Enum):
return self in [ return self in [
BinaryType.POWER, BinaryType.POWER,
BinaryType.MULTIPLICATION, BinaryType.MULTIPLICATION,
BinaryType.MODULO,
BinaryType.ADDITION, BinaryType.ADDITION,
BinaryType.SUBTRACTION, BinaryType.SUBTRACTION,
BinaryType.DIVISION, BinaryType.DIVISION,

@ -38,4 +38,7 @@ class NewArray(Call, OperationWithLValue):
def __str__(self): def __str__(self):
args = [str(a) for a in self.arguments] args = [str(a) for a in self.arguments]
return f"{self.lvalue} = new {self.array_type}{'[]' * self.depth}({','.join(args)})" lvalue = self.lvalue
return (
f"{lvalue}({lvalue.type}) = new {self.array_type}{'[]' * self.depth}({','.join(args)})"
)

@ -104,4 +104,5 @@ class NewContract(Call, OperationWithLValue): # pylint: disable=too-many-instan
if self.call_salt: if self.call_salt:
options += f"salt:{self.call_salt} " options += f"salt:{self.call_salt} "
args = [str(a) for a in self.arguments] args = [str(a) for a in self.arguments]
return f"{self.lvalue} = new {self.contract_name}({','.join(args)}) {options}" lvalue = self.lvalue
return f"{lvalue}({lvalue.type}) = new {self.contract_name}({','.join(args)}) {options}"

@ -39,4 +39,5 @@ class NewStructure(Call, OperationWithLValue):
def __str__(self): def __str__(self):
args = [str(a) for a in self.arguments] args = [str(a) for a in self.arguments]
return f"{self.lvalue} = new {self.structure_name}({','.join(args)})" lvalue = self.lvalue
return f"{lvalue}({lvalue.type}) = new {self.structure_name}({','.join(args)})"

@ -58,7 +58,7 @@ class Unary(OperationWithLValue):
@property @property
def type_str(self): def type_str(self):
return self._type.value return str(self._type)
def __str__(self): def __str__(self):
return f"{self.lvalue} = {self.type_str} {self.rvalue} " return f"{self.lvalue} = {self.type_str} {self.rvalue} "

@ -170,10 +170,9 @@ class ContractSolc(CallerContextExpression):
elif attributes["contractKind"] == "library": elif attributes["contractKind"] == "library":
self._contract.is_library = True self._contract.is_library = True
self._contract.contract_kind = attributes["contractKind"] self._contract.contract_kind = attributes["contractKind"]
self._contract.is_fully_implemented = attributes["fullyImplemented"]
self._contract.is_fully_implemented = attributes["fullyImplemented"]
self._linearized_base_contracts = attributes["linearizedBaseContracts"] self._linearized_base_contracts = attributes["linearizedBaseContracts"]
# self._contract.fullyImplemented = attributes["fullyImplemented"]
# Parse base contract information # Parse base contract information
self._parse_base_contract_info() self._parse_base_contract_info()

@ -1,5 +1,5 @@
import logging import logging
from typing import Dict, Optional, Union, List, TYPE_CHECKING, Tuple from typing import Dict, Optional, Union, List, TYPE_CHECKING, Tuple, Set
from slither.core.cfg.node import NodeType, link_nodes, insert_node, Node from slither.core.cfg.node import NodeType, link_nodes, insert_node, Node
from slither.core.cfg.scope import Scope from slither.core.cfg.scope import Scope
@ -780,6 +780,7 @@ class FunctionSolc(CallerContextExpression):
"nodeType": "Identifier", "nodeType": "Identifier",
"src": v["src"], "src": v["src"],
"name": v["name"], "name": v["name"],
"referencedDeclaration": v["id"],
"typeDescriptions": {"typeString": v["typeDescriptions"]["typeString"]}, "typeDescriptions": {"typeString": v["typeDescriptions"]["typeString"]},
} }
var_identifiers.append(identifier) var_identifiers.append(identifier)
@ -1163,15 +1164,16 @@ class FunctionSolc(CallerContextExpression):
if end_node: if end_node:
for son in node.sons: for son in node.sons:
if son.type == NodeType.CATCH: if son.type == NodeType.CATCH:
self._fix_catch(son, end_node) self._fix_catch(son, end_node, set())
def _fix_catch(self, node: Node, end_node: Node) -> None: def _fix_catch(self, node: Node, end_node: Node, visited: Set[Node]) -> None:
if not node.sons: if not node.sons:
link_nodes(node, end_node) link_nodes(node, end_node)
else: else:
for son in node.sons: for son in node.sons:
if son != end_node: if son != end_node and son not in visited:
self._fix_catch(son, end_node) visited.add(son)
self._fix_catch(son, end_node, visited)
# endregion # endregion
################################################################################### ###################################################################################
@ -1533,8 +1535,7 @@ class FunctionSolc(CallerContextExpression):
endif_node = self._new_node(NodeType.ENDIF, node.source_mapping, node.scope) endif_node = self._new_node(NodeType.ENDIF, node.source_mapping, node.scope)
for father in node.fathers: for father in node.fathers:
father.remove_son(node) father.replace_son(node, condition_node.underlying_node)
father.add_son(condition_node.underlying_node)
condition_node.underlying_node.add_father(father) condition_node.underlying_node.add_father(father)
for son in node.sons: for son in node.sons:

@ -87,6 +87,9 @@ class ModifierSolc(FunctionSolc):
for node in self._node_to_nodesolc.values(): for node in self._node_to_nodesolc.values():
node.analyze_expressions(self) node.analyze_expressions(self)
for yul_parser in self._node_to_yulobject.values():
yul_parser.analyze_expressions()
self._rewrite_ternary_as_if_else() self._rewrite_ternary_as_if_else()
self._remove_alone_endif() self._remove_alone_endif()

@ -15,7 +15,7 @@ ZIP_TYPES_ACCEPTED = {
Export = namedtuple("Export", ["filename", "content"]) Export = namedtuple("Export", ["filename", "content"])
logger = logging.getLogger("Slither") logger = logging.getLogger("Slither-flat")
def save_to_zip(files: List[Export], zip_filename: str, zip_type: str = "lzma"): def save_to_zip(files: List[Export], zip_filename: str, zip_type: str = "lzma"):

@ -11,6 +11,7 @@ from slither.core.declarations import SolidityFunction, EnumContract, StructureC
from slither.core.declarations.contract import Contract from slither.core.declarations.contract import Contract
from slither.core.declarations.function_top_level import FunctionTopLevel from slither.core.declarations.function_top_level import FunctionTopLevel
from slither.core.declarations.top_level import TopLevel from slither.core.declarations.top_level import TopLevel
from slither.core.declarations.solidity_variables import SolidityCustomRevert
from slither.core.solidity_types import MappingType, ArrayType from slither.core.solidity_types import MappingType, ArrayType
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.core.solidity_types.user_defined_type import UserDefinedType from slither.core.solidity_types.user_defined_type import UserDefinedType
@ -23,7 +24,8 @@ from slither.tools.flattening.export.export import (
save_to_disk, save_to_disk,
) )
logger = logging.getLogger("Slither-flattening") logger = logging.getLogger("Slither-flat")
logger.setLevel(logging.INFO)
# index: where to start # index: where to start
# patch_type: # patch_type:
@ -75,6 +77,7 @@ class Flattening:
self._get_source_code_top_level(compilation_unit.structures_top_level) self._get_source_code_top_level(compilation_unit.structures_top_level)
self._get_source_code_top_level(compilation_unit.enums_top_level) self._get_source_code_top_level(compilation_unit.enums_top_level)
self._get_source_code_top_level(compilation_unit.custom_errors)
self._get_source_code_top_level(compilation_unit.variables_top_level) self._get_source_code_top_level(compilation_unit.variables_top_level)
self._get_source_code_top_level(compilation_unit.functions_top_level) self._get_source_code_top_level(compilation_unit.functions_top_level)
@ -249,12 +252,14 @@ class Flattening:
t: Type, t: Type,
contract: Contract, contract: Contract,
exported: Set[str], exported: Set[str],
list_contract: List[Contract], list_contract: Set[Contract],
list_top_level: List[TopLevel], list_top_level: Set[TopLevel],
): ):
if isinstance(t, UserDefinedType): if isinstance(t, UserDefinedType):
t_type = t.type t_type = t.type
if isinstance(t_type, (EnumContract, StructureContract)): if isinstance(t_type, TopLevel):
list_top_level.add(t_type)
elif isinstance(t_type, (EnumContract, StructureContract)):
if t_type.contract != contract and t_type.contract not in exported: if t_type.contract != contract and t_type.contract not in exported:
self._export_list_used_contracts( self._export_list_used_contracts(
t_type.contract, exported, list_contract, list_top_level t_type.contract, exported, list_contract, list_top_level
@ -275,8 +280,8 @@ class Flattening:
self, self,
contract: Contract, contract: Contract,
exported: Set[str], exported: Set[str],
list_contract: List[Contract], list_contract: Set[Contract],
list_top_level: List[TopLevel], list_top_level: Set[TopLevel],
): ):
# TODO: investigate why this happen # TODO: investigate why this happen
if not isinstance(contract, Contract): if not isinstance(contract, Contract):
@ -332,19 +337,21 @@ class Flattening:
for read in ir.read: for read in ir.read:
if isinstance(read, TopLevel): if isinstance(read, TopLevel):
if read not in list_top_level: list_top_level.add(read)
list_top_level.append(read) if isinstance(ir, InternalCall) and isinstance(ir.function, FunctionTopLevel):
if isinstance(ir, InternalCall): list_top_level.add(ir.function)
function_called = ir.function if (
if isinstance(function_called, FunctionTopLevel): isinstance(ir, SolidityCall)
list_top_level.append(function_called) and isinstance(ir.function, SolidityCustomRevert)
and isinstance(ir.function.custom_error, TopLevel)
if contract not in list_contract: ):
list_contract.append(contract) list_top_level.add(ir.function.custom_error)
list_contract.add(contract)
def _export_contract_with_inheritance(self, contract) -> Export: def _export_contract_with_inheritance(self, contract) -> Export:
list_contracts: List[Contract] = [] # will contain contract itself list_contracts: Set[Contract] = set() # will contain contract itself
list_top_level: List[TopLevel] = [] list_top_level: Set[TopLevel] = set()
self._export_list_used_contracts(contract, set(), list_contracts, list_top_level) self._export_list_used_contracts(contract, set(), list_contracts, list_top_level)
path = Path(self._export_path, f"{contract.name}_{uuid.uuid4()}.sol") path = Path(self._export_path, f"{contract.name}_{uuid.uuid4()}.sol")
@ -401,8 +408,8 @@ class Flattening:
def _export_with_import(self) -> List[Export]: def _export_with_import(self) -> List[Export]:
exports: List[Export] = [] exports: List[Export] = []
for contract in self._compilation_unit.contracts: for contract in self._compilation_unit.contracts:
list_contracts: List[Contract] = [] # will contain contract itself list_contracts: Set[Contract] = set() # will contain contract itself
list_top_level: List[TopLevel] = [] list_top_level: Set[TopLevel] = set()
self._export_list_used_contracts(contract, set(), list_contracts, list_top_level) self._export_list_used_contracts(contract, set(), list_contracts, list_top_level)
if list_top_level: if list_top_level:

@ -441,7 +441,7 @@ class SlitherReadStorage:
if "int" in key_type: # without this eth_utils encoding fails if "int" in key_type: # without this eth_utils encoding fails
key = int(key) key = int(key)
key = coerce_type(key_type, key) key = coerce_type(key_type, key)
slot = keccak(encode([key_type, "uint256"], [key, decode("uint256", slot)])) slot = keccak(encode([key_type, "uint256"], [key, decode(["uint256"], slot)[0]]))
if isinstance(target_variable_type.type_to, UserDefinedType) and isinstance( if isinstance(target_variable_type.type_to, UserDefinedType) and isinstance(
target_variable_type.type_to.type, Structure target_variable_type.type_to.type, Structure

@ -1,62 +1,149 @@
# Functions for generating Solidity code # Functions for generating Solidity code
from typing import TYPE_CHECKING, Optional from typing import TYPE_CHECKING, Optional
from slither.utils.type import convert_type_for_solidity_signature_to_string from slither.utils.type import (
convert_type_for_solidity_signature_to_string,
export_nested_types_from_variable,
export_return_type_from_variable,
)
from slither.core.solidity_types import (
Type,
UserDefinedType,
MappingType,
ArrayType,
ElementaryType,
)
from slither.core.declarations import Structure, Enum, Contract
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.declarations import FunctionContract, Structure, Contract from slither.core.declarations import FunctionContract, CustomErrorContract
from slither.core.variables.state_variable import StateVariable
from slither.core.variables.local_variable import LocalVariable
def generate_interface(contract: "Contract") -> str: # pylint: disable=too-many-arguments
def generate_interface(
contract: "Contract",
unroll_structs: bool = True,
include_events: bool = True,
include_errors: bool = True,
include_enums: bool = True,
include_structs: bool = True,
) -> str:
""" """
Generates code for a Solidity interface to the contract. Generates code for a Solidity interface to the contract.
Args: Args:
contract: A Contract object contract: A Contract object.
unroll_structs: Whether to use structures' underlying types instead of the user-defined type (default: True).
include_events: Whether to include event signatures in the interface (default: True).
include_errors: Whether to include custom error signatures in the interface (default: True).
include_enums: Whether to include enum definitions in the interface (default: True).
include_structs: Whether to include struct definitions in the interface (default: True).
Returns: Returns:
A string with the code for an interface, with function stubs for all public or external functions and A string with the code for an interface, with function stubs for all public or external functions and
state variables, as well as any events, custom errors and/or structs declared in the contract. state variables, as well as any events, custom errors and/or structs declared in the contract.
""" """
interface = f"interface I{contract.name} {{\n" interface = f"interface I{contract.name} {{\n"
for event in contract.events: if include_events:
name, args = event.signature for event in contract.events:
interface += f" event {name}({', '.join(args)});\n" name, args = event.signature
for error in contract.custom_errors: interface += f" event {name}({', '.join(args)});\n"
args = [ if include_errors:
convert_type_for_solidity_signature_to_string(arg.type) for error in contract.custom_errors:
.replace("(", "") interface += f" error {generate_custom_error_interface(error, unroll_structs)};\n"
.replace(")", "") if include_enums:
for arg in error.parameters for enum in contract.enums:
] interface += f" enum {enum.name} {{ {', '.join(enum.values)} }}\n"
interface += f" error {error.name}({', '.join(args)});\n" if include_structs:
for enum in contract.enums: for struct in contract.structures:
interface += f" enum {enum.name} {{ {', '.join(enum.values)} }}\n" interface += generate_struct_interface_str(struct, indent=4)
for struct in contract.structures:
interface += generate_struct_interface_str(struct)
for var in contract.state_variables_entry_points: for var in contract.state_variables_entry_points:
interface += f" function {var.signature_str.replace('returns', 'external returns ')};\n" interface += f" function {generate_interface_variable_signature(var, unroll_structs)};\n"
for func in contract.functions_entry_points: for func in contract.functions_entry_points:
if func.is_constructor or func.is_fallback or func.is_receive: if func.is_constructor or func.is_fallback or func.is_receive:
continue continue
interface += f" function {generate_interface_function_signature(func)};\n" interface += (
f" function {generate_interface_function_signature(func, unroll_structs)};\n"
)
interface += "}\n\n" interface += "}\n\n"
return interface return interface
def generate_interface_function_signature(func: "FunctionContract") -> Optional[str]: def generate_interface_variable_signature(
var: "StateVariable", unroll_structs: bool = True
) -> Optional[str]:
if var.visibility in ["private", "internal"]:
return None
if unroll_structs:
params = [
convert_type_for_solidity_signature_to_string(x).replace("(", "").replace(")", "")
for x in export_nested_types_from_variable(var)
]
returns = [
convert_type_for_solidity_signature_to_string(x).replace("(", "").replace(")", "")
for x in export_return_type_from_variable(var)
]
else:
_, params, _ = var.signature
params = [p + " memory" if p in ["bytes", "string"] else p for p in params]
returns = []
_type = var.type
while isinstance(_type, MappingType):
_type = _type.type_to
while isinstance(_type, (ArrayType, UserDefinedType)):
_type = _type.type
ret = str(_type)
if isinstance(_type, Structure) or (isinstance(_type, Type) and _type.is_dynamic):
ret += " memory"
elif isinstance(_type, Contract):
ret = "address"
returns.append(ret)
return f"{var.name}({','.join(params)}) external returns ({', '.join(returns)})"
def generate_interface_function_signature(
func: "FunctionContract", unroll_structs: bool = True
) -> Optional[str]:
""" """
Generates a string of the form: Generates a string of the form:
func_name(type1,type2) external {payable/view/pure} returns (type3) func_name(type1,type2) external {payable/view/pure} returns (type3)
Args: Args:
func: A FunctionContract object func: A FunctionContract object
unroll_structs: Determines whether structs are unrolled into underlying types (default: True)
Returns: Returns:
The function interface as a str (contains the return values). The function interface as a str (contains the return values).
Returns None if the function is private or internal, or is a constructor/fallback/receive. Returns None if the function is private or internal, or is a constructor/fallback/receive.
""" """
name, parameters, return_vars = func.signature def format_var(var: "LocalVariable", unroll: bool) -> str:
if unroll:
return (
convert_type_for_solidity_signature_to_string(var.type)
.replace("(", "")
.replace(")", "")
)
if isinstance(var.type, ArrayType) and isinstance(
var.type.type, (UserDefinedType, ElementaryType)
):
return (
convert_type_for_solidity_signature_to_string(var.type)
.replace("(", "")
.replace(")", "")
+ f" {var.location}"
)
if isinstance(var.type, UserDefinedType):
if isinstance(var.type.type, (Structure, Enum)):
return f"{str(var.type.type)} memory"
if isinstance(var.type.type, Contract):
return "address"
if var.type.is_dynamic:
return f"{var.type} {var.location}"
return str(var.type)
name, _, _ = func.signature
if ( if (
func not in func.contract.functions_entry_points func not in func.contract.functions_entry_points
or func.is_constructor or func.is_constructor
@ -64,26 +151,20 @@ def generate_interface_function_signature(func: "FunctionContract") -> Optional[
or func.is_receive or func.is_receive
): ):
return None return None
view = " view" if func.view else "" view = " view" if func.view and not func.pure else ""
pure = " pure" if func.pure else "" pure = " pure" if func.pure else ""
payable = " payable" if func.payable else "" payable = " payable" if func.payable else ""
returns = [ returns = [format_var(ret, unroll_structs) for ret in func.returns]
convert_type_for_solidity_signature_to_string(ret.type).replace("(", "").replace(")", "") parameters = [format_var(param, unroll_structs) for param in func.parameters]
for ret in func.returns
]
parameters = [
convert_type_for_solidity_signature_to_string(param.type).replace("(", "").replace(")", "")
for param in func.parameters
]
_interface_signature_str = ( _interface_signature_str = (
name + "(" + ",".join(parameters) + ") external" + payable + pure + view name + "(" + ",".join(parameters) + ") external" + payable + pure + view
) )
if len(return_vars) > 0: if len(returns) > 0:
_interface_signature_str += " returns (" + ",".join(returns) + ")" _interface_signature_str += " returns (" + ",".join(returns) + ")"
return _interface_signature_str return _interface_signature_str
def generate_struct_interface_str(struct: "Structure") -> str: def generate_struct_interface_str(struct: "Structure", indent: int = 0) -> str:
""" """
Generates code for a structure declaration in an interface of the form: Generates code for a structure declaration in an interface of the form:
struct struct_name { struct struct_name {
@ -92,13 +173,37 @@ def generate_struct_interface_str(struct: "Structure") -> str:
... ... ... ...
} }
Args: Args:
struct: A Structure object struct: A Structure object.
indent: Number of spaces to indent the code block with.
Returns: Returns:
The structure declaration code as a string. The structure declaration code as a string.
""" """
definition = f" struct {struct.name} {{\n" spaces = ""
for _ in range(0, indent):
spaces += " "
definition = f"{spaces}struct {struct.name} {{\n"
for elem in struct.elems_ordered: for elem in struct.elems_ordered:
definition += f" {elem.type} {elem.name};\n" if isinstance(elem.type, UserDefinedType):
definition += " }\n" if isinstance(elem.type.type, (Structure, Enum)):
definition += f"{spaces} {elem.type.type} {elem.name};\n"
elif isinstance(elem.type.type, Contract):
definition += f"{spaces} address {elem.name};\n"
else:
definition += f"{spaces} {elem.type} {elem.name};\n"
definition += f"{spaces}}}\n"
return definition return definition
def generate_custom_error_interface(
error: "CustomErrorContract", unroll_structs: bool = True
) -> str:
args = [
convert_type_for_solidity_signature_to_string(arg.type).replace("(", "").replace(")", "")
if unroll_structs
else str(arg.type.type)
if isinstance(arg.type, UserDefinedType) and isinstance(arg.type.type, (Structure, Enum))
else str(arg.type)
for arg in error.parameters
]
return f"{error.name}({', '.join(args)})"

@ -1,6 +1,6 @@
from typing import List, Dict, Union from typing import List, Dict, Union
from prettytable import PrettyTable from prettytable.colortable import ColorTable, Themes
class MyPrettyTable: class MyPrettyTable:
@ -11,8 +11,8 @@ class MyPrettyTable:
def add_row(self, row: List[Union[str, List[str]]]) -> None: def add_row(self, row: List[Union[str, List[str]]]) -> None:
self._rows.append(row) self._rows.append(row)
def to_pretty_table(self) -> PrettyTable: def to_pretty_table(self) -> ColorTable:
table = PrettyTable(self._field_names) table = ColorTable(self._field_names, theme=Themes.OCEAN)
for row in self._rows: for row in self._rows:
table.add_row(row) table.add_row(row)
return table return table

@ -197,3 +197,18 @@ def export_return_type_from_variable(
return ret return ret
return [variable_or_type.type] return [variable_or_type.type]
def is_underlying_type_address(t: "Type") -> bool:
"""
Return true if the underlying type is an address
i.e. if the type is an address or a contract
"""
# pylint: disable=import-outside-toplevel
from slither.core.declarations.contract import Contract
if t == ElementaryType("address"):
return True
if isinstance(t, UserDefinedType) and isinstance(t.type, Contract):
return True
return False

@ -10,6 +10,7 @@ from slither.core.declarations import (
Contract, Contract,
EnumContract, EnumContract,
EnumTopLevel, EnumTopLevel,
Enum,
) )
from slither.core.expressions import ( from slither.core.expressions import (
AssignmentOperation, AssignmentOperation,
@ -405,10 +406,13 @@ class ExpressionToSlithIR(ExpressionVisitor):
right = get(expression.expression_right) right = get(expression.expression_right)
operation: Operation operation: Operation
# Left can be a type for abi.decode(var, uint[2]) # Left can be a type for abi.decode(var, uint[2])
if isinstance(left, Type): if isinstance(left, (Type, Contract, Enum)):
# Nested type are not yet supported by abi.decode, so the assumption # Nested type are not yet supported by abi.decode, so the assumption
# Is that the right variable must be a constant # Is that the right variable must be a constant
assert isinstance(right, Constant) assert isinstance(right, Constant)
# Case for abi.decode(var, I[2]) where I is an interface/contract or an enum
if isinstance(left, (Contract, Enum)):
left = UserDefinedType(left)
t = ArrayType(left, int(right.value)) t = ArrayType(left, int(right.value))
set_val(expression, t) set_val(expression, t)
return return
@ -622,7 +626,6 @@ class ExpressionToSlithIR(ExpressionVisitor):
set_val(expression, value) set_val(expression, value)
elif expression.type in [UnaryOperationType.MINUS_PRE]: elif expression.type in [UnaryOperationType.MINUS_PRE]:
lvalue = TemporaryVariable(self._node) lvalue = TemporaryVariable(self._node)
assert isinstance(value.type, ElementaryType)
operation = Binary(lvalue, Constant("0", value.type), value, BinaryType.SUBTRACTION) operation = Binary(lvalue, Constant("0", value.type), value, BinaryType.SUBTRACTION)
operation.set_expression(expression) operation.set_expression(expression)
self._result.append(operation) self._result.append(operation)

@ -0,0 +1,79 @@
# pylint: disable=redefined-outer-name
import os
from pathlib import Path
import tempfile
import shutil
from contextlib import contextmanager
import pytest
from filelock import FileLock
from solc_select import solc_select
from slither import Slither
def pytest_configure(config):
"""Create a temporary directory for the tests to use."""
if is_master():
config.stash["shared_directory"] = tempfile.mkdtemp()
def pytest_unconfigure(config):
"""Remove the temporary directory after the tests are done."""
if is_master():
shutil.rmtree(config.stash["shared_directory"])
def pytest_configure_node(node):
"""Configure each worker node with the shared directory."""
node.workerinput["shared_directory"] = node.config.stash["shared_directory"]
def is_master():
"""Returns True if the current process is the master process (which does not have a worker id)."""
return os.environ.get("PYTEST_XDIST_WORKER") is None
@pytest.fixture
def shared_directory(request):
"""Returns the shared directory for the current process."""
if is_master():
return request.config.stash["shared_directory"]
return request.config.workerinput["shared_directory"]
@pytest.fixture
def solc_binary_path(shared_directory):
"""
Returns the path to the solc binary for the given version.
If the binary is not installed, it will be installed.
"""
def inner(version):
lock = FileLock(f"{shared_directory}/{version}.lock", timeout=60)
with lock:
if not solc_select.artifact_path(version).exists():
print("Installing solc version", version)
solc_select.install_artifacts([version])
return solc_select.artifact_path(version).as_posix()
return inner
@pytest.fixture
def slither_from_source(solc_binary_path):
@contextmanager
def inner(source_code: str, solc_version: str = "0.8.19"):
"""Yields a Slither instance using source_code string and solc_version.
Creates a temporary file and compiles with solc_version.
"""
fname = ""
try:
with tempfile.NamedTemporaryFile(mode="w", suffix=".sol", delete=False) as f:
fname = f.name
f.write(source_code)
solc_path = solc_binary_path(solc_version)
yield Slither(fname, solc=solc_path)
finally:
Path(fname).unlink()
return inner

@ -3,7 +3,6 @@ import pytest
from crytic_compile import CryticCompile from crytic_compile import CryticCompile
from crytic_compile.platform.solc_standard_json import SolcStandardJson from crytic_compile.platform.solc_standard_json import SolcStandardJson
from solc_select import solc_select
from slither import Slither from slither import Slither
@ -24,8 +23,8 @@ def test_node_modules() -> None:
_run_all_detectors(slither) _run_all_detectors(slither)
def test_contract_name_collisions() -> None: def test_contract_name_collision(solc_binary_path) -> None:
solc_select.switch_global_version("0.8.0", always_install=True) solc_path = solc_binary_path("0.8.0")
standard_json = SolcStandardJson() standard_json = SolcStandardJson()
standard_json.add_source_file( standard_json.add_source_file(
Path(TEST_DATA_DIR, "test_contract_name_collisions", "a.sol").as_posix() Path(TEST_DATA_DIR, "test_contract_name_collisions", "a.sol").as_posix()
@ -34,13 +33,13 @@ def test_contract_name_collisions() -> None:
Path(TEST_DATA_DIR, "test_contract_name_collisions", "b.sol").as_posix() Path(TEST_DATA_DIR, "test_contract_name_collisions", "b.sol").as_posix()
) )
compilation = CryticCompile(standard_json) compilation = CryticCompile(standard_json, solc=solc_path)
slither = Slither(compilation) slither = Slither(compilation)
_run_all_detectors(slither) _run_all_detectors(slither)
def test_cycle() -> None: def test_cycle(solc_binary_path) -> None:
solc_select.switch_global_version("0.8.0", always_install=True) solc_path = solc_binary_path("0.8.0")
slither = Slither(Path(TEST_DATA_DIR, "test_cyclic_import", "a.sol").as_posix()) slither = Slither(Path(TEST_DATA_DIR, "test_cyclic_import", "a.sol").as_posix(), solc=solc_path)
_run_all_detectors(slither) _run_all_detectors(slither)

@ -0,0 +1,18 @@
Function A.bad3() (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#39-41) trigger an abi encoding bug:
- b = abi.encode(s) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#40)
Function A.bad0() (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#21-23) trigger an abi encoding bug:
- this.bad0_external(bad_arr) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#22)
Function A.bad4() (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#44-46) trigger an abi encoding bug:
- event1_bad(bad_arr) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#45)
Function A.bad2() (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#34-36) trigger an abi encoding bug:
- b = abi.encode(bad_arr) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#35)
Function A.bad1(A.S[3]) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#29-31) trigger an abi encoding bug:
- this.bad1_external(s) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#30)
Function A.bad5() (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#49-51) trigger an abi encoding bug:
- event2_bad(s) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#50)

@ -0,0 +1,18 @@
Function A.bad5() (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#49-51) trigger an abi encoding bug:
- event2_bad(s) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#50)
Function A.bad0() (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#21-23) trigger an abi encoding bug:
- this.bad0_external(bad_arr) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#22)
Function A.bad4() (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#44-46) trigger an abi encoding bug:
- event1_bad(bad_arr) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#45)
Function A.bad2() (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#34-36) trigger an abi encoding bug:
- b = abi.encode(bad_arr) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#35)
Function A.bad1(A.S[3]) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#29-31) trigger an abi encoding bug:
- this.bad1_external(s) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#30)
Function A.bad3() (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#39-41) trigger an abi encoding bug:
- b = abi.encode(s) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#40)

@ -0,0 +1,6 @@
C.bad4(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.4.25/arbitrary_send_erc20.sol#65-67) uses arbitrary from in transferFrom: SafeERC20.safeTransferFrom(erc20,from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.4.25/arbitrary_send_erc20.sol#66)
C.bad1(address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.4.25/arbitrary_send_erc20.sol#35-37) uses arbitrary from in transferFrom: erc20.transferFrom(notsend,to,am) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.4.25/arbitrary_send_erc20.sol#36)
C.bad3(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.4.25/arbitrary_send_erc20.sol#57-59) uses arbitrary from in transferFrom: erc20.safeTransferFrom(from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.4.25/arbitrary_send_erc20.sol#58)

@ -0,0 +1,6 @@
C.bad4(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.5.16/arbitrary_send_erc20.sol#65-67) uses arbitrary from in transferFrom: SafeERC20.safeTransferFrom(erc20,from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.5.16/arbitrary_send_erc20.sol#66)
C.bad3(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.5.16/arbitrary_send_erc20.sol#57-59) uses arbitrary from in transferFrom: erc20.safeTransferFrom(from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.5.16/arbitrary_send_erc20.sol#58)
C.bad1(address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.5.16/arbitrary_send_erc20.sol#35-37) uses arbitrary from in transferFrom: erc20.transferFrom(notsend,to,am) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.5.16/arbitrary_send_erc20.sol#36)

@ -0,0 +1,6 @@
C.bad1(address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.6.11/arbitrary_send_erc20.sol#35-37) uses arbitrary from in transferFrom: erc20.transferFrom(notsend,to,am) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.6.11/arbitrary_send_erc20.sol#36)
C.bad3(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.6.11/arbitrary_send_erc20.sol#57-59) uses arbitrary from in transferFrom: erc20.safeTransferFrom(from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.6.11/arbitrary_send_erc20.sol#58)
C.bad4(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.6.11/arbitrary_send_erc20.sol#65-67) uses arbitrary from in transferFrom: SafeERC20.safeTransferFrom(erc20,from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.6.11/arbitrary_send_erc20.sol#66)

@ -0,0 +1,6 @@
C.bad4(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.7.6/arbitrary_send_erc20.sol#65-67) uses arbitrary from in transferFrom: SafeERC20.safeTransferFrom(erc20,from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.7.6/arbitrary_send_erc20.sol#66)
C.bad3(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.7.6/arbitrary_send_erc20.sol#57-59) uses arbitrary from in transferFrom: erc20.safeTransferFrom(from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.7.6/arbitrary_send_erc20.sol#58)
C.bad1(address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.7.6/arbitrary_send_erc20.sol#35-37) uses arbitrary from in transferFrom: erc20.transferFrom(notsend,to,am) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.7.6/arbitrary_send_erc20.sol#36)

@ -0,0 +1,2 @@
T.bad(address) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20_inheritance.sol#11-13) uses arbitrary from in transferFrom: erc20.safeTransferFrom(from,address(0x1),90) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20_inheritance.sol#12)

@ -0,0 +1,6 @@
C.bad1(address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20.sol#35-37) uses arbitrary from in transferFrom: erc20.transferFrom(notsend,to,am) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20.sol#36)
C.bad3(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20.sol#57-59) uses arbitrary from in transferFrom: erc20.safeTransferFrom(from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20.sol#58)
C.bad4(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20.sol#65-67) uses arbitrary from in transferFrom: SafeERC20.safeTransferFrom(erc20,from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20.sol#66)

@ -0,0 +1,8 @@
C.int_transferFrom(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#42-45) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#44)
C.bad3(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#47-50) uses arbitrary from in transferFrom in combination with permit: erc20.safeTransferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#49)
C.bad4(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#52-55) uses arbitrary from in transferFrom in combination with permit: SafeERC20.safeTransferFrom(erc20,from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#54)
C.bad1(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#32-35) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#34)

@ -0,0 +1,8 @@
C.int_transferFrom(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#42-45) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#44)
C.bad4(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#52-55) uses arbitrary from in transferFrom in combination with permit: SafeERC20.safeTransferFrom(erc20,from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#54)
C.bad3(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#47-50) uses arbitrary from in transferFrom in combination with permit: erc20.safeTransferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#49)
C.bad1(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#32-35) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#34)

@ -0,0 +1,8 @@
C.bad3(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#47-50) uses arbitrary from in transferFrom in combination with permit: erc20.safeTransferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#49)
C.bad4(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#52-55) uses arbitrary from in transferFrom in combination with permit: SafeERC20.safeTransferFrom(erc20,from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#54)
C.int_transferFrom(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#42-45) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#44)
C.bad1(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#32-35) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#34)

@ -0,0 +1,8 @@
C.int_transferFrom(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#42-45) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#44)
C.bad1(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#32-35) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#34)
C.bad4(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#52-55) uses arbitrary from in transferFrom in combination with permit: SafeERC20.safeTransferFrom(erc20,from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#54)
C.bad3(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#47-50) uses arbitrary from in transferFrom in combination with permit: erc20.safeTransferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#49)

@ -0,0 +1,8 @@
C.bad3(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#47-50) uses arbitrary from in transferFrom in combination with permit: erc20.safeTransferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#49)
C.bad4(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#52-55) uses arbitrary from in transferFrom in combination with permit: SafeERC20.safeTransferFrom(erc20,from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#54)
C.int_transferFrom(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#42-45) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#44)
C.bad1(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#32-35) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#34)

@ -0,0 +1,8 @@
Test.indirect() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.4.25/arbitrary_send_eth.sol#19-21) sends eth to arbitrary user
Dangerous calls:
- destination.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.4.25/arbitrary_send_eth.sol#20)
Test.direct() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.4.25/arbitrary_send_eth.sol#11-13) sends eth to arbitrary user
Dangerous calls:
- msg.sender.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.4.25/arbitrary_send_eth.sol#12)

@ -0,0 +1,8 @@
Test.direct() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.5.16/arbitrary_send_eth.sol#11-13) sends eth to arbitrary user
Dangerous calls:
- msg.sender.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.5.16/arbitrary_send_eth.sol#12)
Test.indirect() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.5.16/arbitrary_send_eth.sol#19-21) sends eth to arbitrary user
Dangerous calls:
- destination.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.5.16/arbitrary_send_eth.sol#20)

@ -0,0 +1,8 @@
Test.indirect() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#19-21) sends eth to arbitrary user
Dangerous calls:
- destination.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#20)
Test.direct() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#11-13) sends eth to arbitrary user
Dangerous calls:
- msg.sender.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#12)

@ -0,0 +1,8 @@
Test.direct() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#11-13) sends eth to arbitrary user
Dangerous calls:
- msg.sender.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#12)
Test.indirect() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#19-21) sends eth to arbitrary user
Dangerous calls:
- destination.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#20)

@ -0,0 +1,12 @@
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#39)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#25-28)which only takes arrays by value
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#39)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#21-23)which only takes arrays by value
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#2)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#21-23)which only takes arrays by value
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#2)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#25-28)which only takes arrays by value
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#11)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#25-28)which only takes arrays by value
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#11)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#21-23)which only takes arrays by value

@ -0,0 +1,12 @@
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#39)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#25-28)which only takes arrays by value
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#39)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#21-23)which only takes arrays by value
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#2)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#21-23)which only takes arrays by value
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#2)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#25-28)which only takes arrays by value
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#11)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#25-28)which only takes arrays by value
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#11)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#21-23)which only takes arrays by value

@ -0,0 +1,12 @@
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#39)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#25-28)which only takes arrays by value
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#39)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#21-23)which only takes arrays by value
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#2)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#21-23)which only takes arrays by value
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#2)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#25-28)which only takes arrays by value
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#11)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#25-28)which only takes arrays by value
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#11)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#21-23)which only takes arrays by value

@ -0,0 +1,12 @@
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#39)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#25-28)which only takes arrays by value
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#39)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#21-23)which only takes arrays by value
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#2)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#21-23)which only takes arrays by value
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#2)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#25-28)which only takes arrays by value
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#11)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#25-28)which only takes arrays by value
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#11)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#21-23)which only takes arrays by value

@ -0,0 +1,9 @@
ArrayLengthAssignment (tests/e2e/detectors/test_data/controlled-array-length/0.4.25/array_length_assignment.sol#1-46) contract sets array length with a user-controlled value:
- b.subStruct.x.length = param + 1 (tests/e2e/detectors/test_data/controlled-array-length/0.4.25/array_length_assignment.sol#41)
ArrayLengthAssignment (tests/e2e/detectors/test_data/controlled-array-length/0.4.25/array_length_assignment.sol#1-46) contract sets array length with a user-controlled value:
- a.x.length = param (tests/e2e/detectors/test_data/controlled-array-length/0.4.25/array_length_assignment.sol#36)
ArrayLengthAssignment (tests/e2e/detectors/test_data/controlled-array-length/0.4.25/array_length_assignment.sol#1-46) contract sets array length with a user-controlled value:
- arr.length = param (tests/e2e/detectors/test_data/controlled-array-length/0.4.25/array_length_assignment.sol#26)

@ -0,0 +1,9 @@
ArrayLengthAssignment (tests/e2e/detectors/test_data/controlled-array-length/0.5.16/array_length_assignment.sol#1-46) contract sets array length with a user-controlled value:
- b.subStruct.x.length = param + 1 (tests/e2e/detectors/test_data/controlled-array-length/0.5.16/array_length_assignment.sol#41)
ArrayLengthAssignment (tests/e2e/detectors/test_data/controlled-array-length/0.5.16/array_length_assignment.sol#1-46) contract sets array length with a user-controlled value:
- a.x.length = param (tests/e2e/detectors/test_data/controlled-array-length/0.5.16/array_length_assignment.sol#36)
ArrayLengthAssignment (tests/e2e/detectors/test_data/controlled-array-length/0.5.16/array_length_assignment.sol#1-46) contract sets array length with a user-controlled value:
- arr.length = param (tests/e2e/detectors/test_data/controlled-array-length/0.5.16/array_length_assignment.sol#26)

@ -0,0 +1,3 @@
GetCode.at(address) (tests/e2e/detectors/test_data/assembly/0.4.25/inline_assembly_contract.sol#6-20) uses assembly
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.4.25/inline_assembly_contract.sol#7-20)

@ -0,0 +1,6 @@
VectorSum.sumPureAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.4.25/inline_assembly_library.sol#25-47) uses assembly
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.4.25/inline_assembly_library.sol#26-47)
VectorSum.sumAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.4.25/inline_assembly_library.sol#16-22) uses assembly
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.4.25/inline_assembly_library.sol#18-21)

@ -0,0 +1,3 @@
GetCode.at(address) (tests/e2e/detectors/test_data/assembly/0.5.16/inline_assembly_contract.sol#6-20) uses assembly
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.5.16/inline_assembly_contract.sol#7-19)

@ -0,0 +1,6 @@
VectorSum.sumAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.5.16/inline_assembly_library.sol#16-22) uses assembly
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.5.16/inline_assembly_library.sol#18-20)
VectorSum.sumPureAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.5.16/inline_assembly_library.sol#25-47) uses assembly
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.5.16/inline_assembly_library.sol#26-46)

@ -0,0 +1,3 @@
GetCode.at(address) (tests/e2e/detectors/test_data/assembly/0.6.11/inline_assembly_contract.sol#4-18) uses assembly
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.6.11/inline_assembly_contract.sol#5-17)

@ -0,0 +1,6 @@
VectorSum.sumAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.6.11/inline_assembly_library.sol#14-20) uses assembly
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.6.11/inline_assembly_library.sol#16-18)
VectorSum.sumPureAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.6.11/inline_assembly_library.sol#23-45) uses assembly
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.6.11/inline_assembly_library.sol#24-44)

@ -0,0 +1,3 @@
GetCode.at(address) (tests/e2e/detectors/test_data/assembly/0.7.6/inline_assembly_contract.sol#4-18) uses assembly
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.7.6/inline_assembly_contract.sol#5-17)

@ -0,0 +1,6 @@
VectorSum.sumAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.7.6/inline_assembly_library.sol#14-20) uses assembly
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.7.6/inline_assembly_library.sol#16-18)
VectorSum.sumPureAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.7.6/inline_assembly_library.sol#23-45) uses assembly
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.7.6/inline_assembly_library.sol#24-44)

@ -0,0 +1,12 @@
A.bad2() (tests/e2e/detectors/test_data/assert-state-change/0.4.25/assert_state_change.sol#19-21) has an assert() call which possibly changes state.
-assert(bool)(bad2_callee()) (tests/e2e/detectors/test_data/assert-state-change/0.4.25/assert_state_change.sol#20)
Consider using require() or change the invariant to not modify the state.
A.bad0() (tests/e2e/detectors/test_data/assert-state-change/0.4.25/assert_state_change.sol#6-8) has an assert() call which possibly changes state.
-assert(bool)((s_a += 1) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.4.25/assert_state_change.sol#7)
Consider using require() or change the invariant to not modify the state.
A.bad1(uint256) (tests/e2e/detectors/test_data/assert-state-change/0.4.25/assert_state_change.sol#11-13) has an assert() call which possibly changes state.
-assert(bool)((s_a += a) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.4.25/assert_state_change.sol#12)
Consider using require() or change the invariant to not modify the state.

@ -0,0 +1,12 @@
A.bad1(uint256) (tests/e2e/detectors/test_data/assert-state-change/0.5.16/assert_state_change.sol#11-13) has an assert() call which possibly changes state.
-assert(bool)((s_a += a) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.5.16/assert_state_change.sol#12)
Consider using require() or change the invariant to not modify the state.
A.bad2() (tests/e2e/detectors/test_data/assert-state-change/0.5.16/assert_state_change.sol#19-21) has an assert() call which possibly changes state.
-assert(bool)(bad2_callee()) (tests/e2e/detectors/test_data/assert-state-change/0.5.16/assert_state_change.sol#20)
Consider using require() or change the invariant to not modify the state.
A.bad0() (tests/e2e/detectors/test_data/assert-state-change/0.5.16/assert_state_change.sol#6-8) has an assert() call which possibly changes state.
-assert(bool)((s_a += 1) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.5.16/assert_state_change.sol#7)
Consider using require() or change the invariant to not modify the state.

@ -0,0 +1,12 @@
A.bad0() (tests/e2e/detectors/test_data/assert-state-change/0.6.11/assert_state_change.sol#6-8) has an assert() call which possibly changes state.
-assert(bool)((s_a += 1) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.6.11/assert_state_change.sol#7)
Consider using require() or change the invariant to not modify the state.
A.bad1(uint256) (tests/e2e/detectors/test_data/assert-state-change/0.6.11/assert_state_change.sol#11-13) has an assert() call which possibly changes state.
-assert(bool)((s_a += a) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.6.11/assert_state_change.sol#12)
Consider using require() or change the invariant to not modify the state.
A.bad2() (tests/e2e/detectors/test_data/assert-state-change/0.6.11/assert_state_change.sol#19-21) has an assert() call which possibly changes state.
-assert(bool)(bad2_callee()) (tests/e2e/detectors/test_data/assert-state-change/0.6.11/assert_state_change.sol#20)
Consider using require() or change the invariant to not modify the state.

@ -0,0 +1,12 @@
A.bad2() (tests/e2e/detectors/test_data/assert-state-change/0.7.6/assert_state_change.sol#19-21) has an assert() call which possibly changes state.
-assert(bool)(bad2_callee()) (tests/e2e/detectors/test_data/assert-state-change/0.7.6/assert_state_change.sol#20)
Consider using require() or change the invariant to not modify the state.
A.bad1(uint256) (tests/e2e/detectors/test_data/assert-state-change/0.7.6/assert_state_change.sol#11-13) has an assert() call which possibly changes state.
-assert(bool)((s_a += a) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.7.6/assert_state_change.sol#12)
Consider using require() or change the invariant to not modify the state.
A.bad0() (tests/e2e/detectors/test_data/assert-state-change/0.7.6/assert_state_change.sol#6-8) has an assert() call which possibly changes state.
-assert(bool)((s_a += 1) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.7.6/assert_state_change.sol#7)
Consider using require() or change the invariant to not modify the state.

@ -0,0 +1,2 @@
Backdoor function found in C.i_am_a_backdoor() (tests/e2e/detectors/test_data/backdoor/0.4.25/backdoor.sol#4-6)

@ -0,0 +1,2 @@
Backdoor function found in C.i_am_a_backdoor() (tests/e2e/detectors/test_data/backdoor/0.5.16/backdoor.sol#4-6)

@ -0,0 +1,2 @@
Backdoor function found in C.i_am_a_backdoor() (tests/e2e/detectors/test_data/backdoor/0.6.11/backdoor.sol#4-6)

@ -0,0 +1,2 @@
Backdoor function found in C.i_am_a_backdoor() (tests/e2e/detectors/test_data/backdoor/0.7.6/backdoor.sol#4-6)

@ -0,0 +1,8 @@
BadPRNG.bad1() (tests/e2e/detectors/test_data/weak-prng/0.4.25/bad_prng.sol#8-10) uses a weak PRNG: "i = now % 10 (tests/e2e/detectors/test_data/weak-prng/0.4.25/bad_prng.sol#9)"
BadPRNG.bad2() (tests/e2e/detectors/test_data/weak-prng/0.4.25/bad_prng.sol#12-14) uses a weak PRNG: "i = uint256(blockhash(uint256)(10000)) % 10 (tests/e2e/detectors/test_data/weak-prng/0.4.25/bad_prng.sol#13)"
BadPRNG.bad3() (tests/e2e/detectors/test_data/weak-prng/0.4.25/bad_prng.sol#20-22) uses a weak PRNG: "i = foo() % 10 (tests/e2e/detectors/test_data/weak-prng/0.4.25/bad_prng.sol#21)"
BadPRNG.bad0() (tests/e2e/detectors/test_data/weak-prng/0.4.25/bad_prng.sol#4-6) uses a weak PRNG: "i = block.timestamp % 10 (tests/e2e/detectors/test_data/weak-prng/0.4.25/bad_prng.sol#5)"

@ -0,0 +1,8 @@
BadPRNG.bad1() (tests/e2e/detectors/test_data/weak-prng/0.5.16/bad_prng.sol#8-10) uses a weak PRNG: "i = now % 10 (tests/e2e/detectors/test_data/weak-prng/0.5.16/bad_prng.sol#9)"
BadPRNG.bad0() (tests/e2e/detectors/test_data/weak-prng/0.5.16/bad_prng.sol#4-6) uses a weak PRNG: "i = block.timestamp % 10 (tests/e2e/detectors/test_data/weak-prng/0.5.16/bad_prng.sol#5)"
BadPRNG.bad2() (tests/e2e/detectors/test_data/weak-prng/0.5.16/bad_prng.sol#12-14) uses a weak PRNG: "i = uint256(blockhash(uint256)(10000)) % 10 (tests/e2e/detectors/test_data/weak-prng/0.5.16/bad_prng.sol#13)"
BadPRNG.bad3() (tests/e2e/detectors/test_data/weak-prng/0.5.16/bad_prng.sol#20-22) uses a weak PRNG: "i = foo() % 10 (tests/e2e/detectors/test_data/weak-prng/0.5.16/bad_prng.sol#21)"

@ -0,0 +1,8 @@
BadPRNG.bad1() (tests/e2e/detectors/test_data/weak-prng/0.6.11/bad_prng.sol#8-10) uses a weak PRNG: "i = now % 10 (tests/e2e/detectors/test_data/weak-prng/0.6.11/bad_prng.sol#9)"
BadPRNG.bad0() (tests/e2e/detectors/test_data/weak-prng/0.6.11/bad_prng.sol#4-6) uses a weak PRNG: "i = block.timestamp % 10 (tests/e2e/detectors/test_data/weak-prng/0.6.11/bad_prng.sol#5)"
BadPRNG.bad2() (tests/e2e/detectors/test_data/weak-prng/0.6.11/bad_prng.sol#12-14) uses a weak PRNG: "i = uint256(blockhash(uint256)(10000)) % 10 (tests/e2e/detectors/test_data/weak-prng/0.6.11/bad_prng.sol#13)"
BadPRNG.bad3() (tests/e2e/detectors/test_data/weak-prng/0.6.11/bad_prng.sol#20-22) uses a weak PRNG: "i = foo() % 10 (tests/e2e/detectors/test_data/weak-prng/0.6.11/bad_prng.sol#21)"

@ -0,0 +1,8 @@
BadPRNG.bad3() (tests/e2e/detectors/test_data/weak-prng/0.7.6/bad_prng.sol#20-22) uses a weak PRNG: "i = foo() % 10 (tests/e2e/detectors/test_data/weak-prng/0.7.6/bad_prng.sol#21)"
BadPRNG.bad2() (tests/e2e/detectors/test_data/weak-prng/0.7.6/bad_prng.sol#12-14) uses a weak PRNG: "i = uint256(blockhash(uint256)(10000)) % 10 (tests/e2e/detectors/test_data/weak-prng/0.7.6/bad_prng.sol#13)"
BadPRNG.bad1() (tests/e2e/detectors/test_data/weak-prng/0.7.6/bad_prng.sol#8-10) uses a weak PRNG: "i = block.timestamp % 10 (tests/e2e/detectors/test_data/weak-prng/0.7.6/bad_prng.sol#9)"
BadPRNG.bad0() (tests/e2e/detectors/test_data/weak-prng/0.7.6/bad_prng.sol#4-6) uses a weak PRNG: "i = block.timestamp % 10 (tests/e2e/detectors/test_data/weak-prng/0.7.6/bad_prng.sol#5)"

@ -0,0 +1,3 @@
MyConc.bad1(bool) (tests/e2e/detectors/test_data/boolean-cst/0.4.25/boolean-constant-misuse.sol#9-11) uses a Boolean constant improperly:
-(b || true) (tests/e2e/detectors/test_data/boolean-cst/0.4.25/boolean-constant-misuse.sol#10)

@ -0,0 +1,3 @@
MyConc.bad1(bool) (tests/e2e/detectors/test_data/boolean-cst/0.5.16/boolean-constant-misuse.sol#9-11) uses a Boolean constant improperly:
-(b || true) (tests/e2e/detectors/test_data/boolean-cst/0.5.16/boolean-constant-misuse.sol#10)

@ -0,0 +1,3 @@
MyConc.bad1(bool) (tests/e2e/detectors/test_data/boolean-cst/0.6.11/boolean-constant-misuse.sol#9-11) uses a Boolean constant improperly:
-(b || true) (tests/e2e/detectors/test_data/boolean-cst/0.6.11/boolean-constant-misuse.sol#10)

@ -0,0 +1,3 @@
MyConc.bad1(bool) (tests/e2e/detectors/test_data/boolean-cst/0.7.6/boolean-constant-misuse.sol#9-11) uses a Boolean constant improperly:
-(b || true) (tests/e2e/detectors/test_data/boolean-cst/0.7.6/boolean-constant-misuse.sol#10)

@ -0,0 +1,3 @@
MyConc.bad1(bool) (tests/e2e/detectors/test_data/boolean-equal/0.4.25/boolean-constant-equality.sol#7-9) compares to a boolean constant:
-(b == true) (tests/e2e/detectors/test_data/boolean-equal/0.4.25/boolean-constant-equality.sol#8)

@ -0,0 +1,3 @@
MyConc.bad1(bool) (tests/e2e/detectors/test_data/boolean-equal/0.5.16/boolean-constant-equality.sol#7-9) compares to a boolean constant:
-(b == true) (tests/e2e/detectors/test_data/boolean-equal/0.5.16/boolean-constant-equality.sol#8)

@ -0,0 +1,3 @@
MyConc.bad1(bool) (tests/e2e/detectors/test_data/boolean-equal/0.6.11/boolean-constant-equality.sol#7-9) compares to a boolean constant:
-(b == true) (tests/e2e/detectors/test_data/boolean-equal/0.6.11/boolean-constant-equality.sol#8)

@ -0,0 +1,3 @@
MyConc.bad1(bool) (tests/e2e/detectors/test_data/boolean-equal/0.7.6/boolean-constant-equality.sol#7-9) compares to a boolean constant:
-(b == true) (tests/e2e/detectors/test_data/boolean-equal/0.7.6/boolean-constant-equality.sol#8)

@ -0,0 +1,26 @@
Reserved.mutable (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#32) (state variable) shadows built-in symbol"
ExtendedContract.ecrecover (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#11) (state variable) shadows built-in symbol"
FurtherExtendedContract.require().keccak256 (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#25) (local variable) shadows built-in symbol"
FurtherExtendedContract.abi (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#21) (state variable) shadows built-in symbol"
BaseContract.blockhash (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#4) (state variable) shadows built-in symbol"
FurtherExtendedContract.this (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#20) (state variable) shadows built-in symbol"
BaseContract.now (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#5) (state variable) shadows built-in symbol"
BaseContractrevert(bool) (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#7) (event) shadows built-in symbol"
ExtendedContract.assert(bool).msg (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#14) (local variable) shadows built-in symbol"
ExtendedContract.assert(bool) (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#13-15) (function) shadows built-in symbol"
FurtherExtendedContract.require().sha3 (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#26) (local variable) shadows built-in symbol"
FurtherExtendedContract.blockhash (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#19) (state variable) shadows built-in symbol"
FurtherExtendedContract.require() (tests/e2e/detectors/test_data/shadowing-builtin/0.4.25/shadowing_builtin_symbols.sol#23-28) (modifier) shadows built-in symbol"

@ -0,0 +1,24 @@
ExtendedContract.ecrecover (tests/e2e/detectors/test_data/shadowing-builtin/0.5.16/shadowing_builtin_symbols.sol#11) (state variable) shadows built-in symbol"
FurtherExtendedContract.require().keccak256 (tests/e2e/detectors/test_data/shadowing-builtin/0.5.16/shadowing_builtin_symbols.sol#25) (local variable) shadows built-in symbol"
FurtherExtendedContract.abi (tests/e2e/detectors/test_data/shadowing-builtin/0.5.16/shadowing_builtin_symbols.sol#21) (state variable) shadows built-in symbol"
BaseContract.blockhash (tests/e2e/detectors/test_data/shadowing-builtin/0.5.16/shadowing_builtin_symbols.sol#4) (state variable) shadows built-in symbol"
FurtherExtendedContract.this (tests/e2e/detectors/test_data/shadowing-builtin/0.5.16/shadowing_builtin_symbols.sol#20) (state variable) shadows built-in symbol"
BaseContract.now (tests/e2e/detectors/test_data/shadowing-builtin/0.5.16/shadowing_builtin_symbols.sol#5) (state variable) shadows built-in symbol"
BaseContractrevert(bool) (tests/e2e/detectors/test_data/shadowing-builtin/0.5.16/shadowing_builtin_symbols.sol#7) (event) shadows built-in symbol"
ExtendedContract.assert(bool).msg (tests/e2e/detectors/test_data/shadowing-builtin/0.5.16/shadowing_builtin_symbols.sol#14) (local variable) shadows built-in symbol"
ExtendedContract.assert(bool) (tests/e2e/detectors/test_data/shadowing-builtin/0.5.16/shadowing_builtin_symbols.sol#13-15) (function) shadows built-in symbol"
FurtherExtendedContract.require().sha3 (tests/e2e/detectors/test_data/shadowing-builtin/0.5.16/shadowing_builtin_symbols.sol#26) (local variable) shadows built-in symbol"
FurtherExtendedContract.blockhash (tests/e2e/detectors/test_data/shadowing-builtin/0.5.16/shadowing_builtin_symbols.sol#19) (state variable) shadows built-in symbol"
FurtherExtendedContract.require() (tests/e2e/detectors/test_data/shadowing-builtin/0.5.16/shadowing_builtin_symbols.sol#23-28) (modifier) shadows built-in symbol"

@ -0,0 +1,2 @@
Constant.test_assembly_bug() (tests/e2e/detectors/test_data/constant-function-asm/0.4.25/constant.sol#22-24) is declared view but contains assembly code

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

Loading…
Cancel
Save