From 114dc2eecaff3262472645f19f961971ee448de5 Mon Sep 17 00:00:00 2001 From: Alexis Date: Mon, 8 Apr 2024 11:43:42 +0200 Subject: [PATCH 01/40] Fix #2266 where the type of functions when used as RValues was not properly printed. --- slither/slithir/operations/assignment.py | 13 +++++++++++-- .../test_data/test_printer_slithir/bug-2266.sol | 13 +++++++++++++ tests/e2e/printers/test_printers.py | 16 ++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 tests/e2e/printers/test_data/test_printer_slithir/bug-2266.sol diff --git a/slither/slithir/operations/assignment.py b/slither/slithir/operations/assignment.py index 1f29ceb7b1..ab6637faa0 100644 --- a/slither/slithir/operations/assignment.py +++ b/slither/slithir/operations/assignment.py @@ -45,10 +45,19 @@ def rvalue(self) -> Union[RVALUE, Function, TupleVariable]: def __str__(self) -> str: lvalue = self.lvalue + + # When rvalues are functions, we want to properly display their return type + # Fix: https://github.com/crytic/slither/issues/2266 + if isinstance(self.rvalue.type, list): + rvalue_type = ",".join(f"{rvalue_type}" for rvalue_type in self.rvalue.type) + else: + rvalue_type = f"{self.rvalue.type}" + assert lvalue if lvalue and isinstance(lvalue, ReferenceVariable): points = lvalue.points_to while isinstance(points, ReferenceVariable): points = points.points_to - 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}) (->{points}) := {self.rvalue}({rvalue_type})" + + return f"{lvalue}({lvalue.type}) := {self.rvalue}({rvalue_type})" diff --git a/tests/e2e/printers/test_data/test_printer_slithir/bug-2266.sol b/tests/e2e/printers/test_data/test_printer_slithir/bug-2266.sol new file mode 100644 index 0000000000..5c11a29141 --- /dev/null +++ b/tests/e2e/printers/test_data/test_printer_slithir/bug-2266.sol @@ -0,0 +1,13 @@ +pragma solidity ^0.8.0; + +contract A { + function add(uint256 a, uint256 b) public returns (uint256) { + return a + b; + } +} + +contract B is A { + function assignFunction() public { + function(uint256, uint256) returns (uint256) myFunction = super.add; + } +} \ No newline at end of file diff --git a/tests/e2e/printers/test_printers.py b/tests/e2e/printers/test_printers.py index 26429d3381..b7cd4d3b6b 100644 --- a/tests/e2e/printers/test_printers.py +++ b/tests/e2e/printers/test_printers.py @@ -7,6 +7,7 @@ from slither import Slither from slither.printers.inheritance.inheritance_graph import PrinterInheritanceGraph +from slither.printers.summary.slithir import PrinterSlithIR TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" @@ -34,3 +35,18 @@ def test_inheritance_printer(solc_binary_path) -> None: assert counter["B -> A"] == 2 assert counter["C -> A"] == 1 + + +def test_slithir_printer(solc_binary_path) -> None: + solc_path = solc_binary_path("0.8.0") + standard_json = SolcStandardJson() + standard_json.add_source_file( + Path(TEST_DATA_DIR, "test_printer_slithir", "bug-2266.sol").as_posix() + ) + compilation = CryticCompile(standard_json, solc=solc_path) + slither = Slither(compilation) + + printer = PrinterSlithIR(slither, logger=None) + output = printer.output("test_printer_slithir.dot") + + assert "slither.core.solidity_types" not in output.data["description"] From c6db465c5f8523748a8da472cd4d0f1dd61fa828 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 10 May 2024 07:57:01 -0500 Subject: [PATCH 02/40] chore: recommend upgrading in issue template --- .github/ISSUE_TEMPLATE/bug_report.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index df9dd7da2c..f1b3a4f4f2 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -3,9 +3,13 @@ body: - attributes: value: | - Please check the issues tab to avoid duplicates. + Please check the issues tab to avoid duplicates, and + confirm that the bug exists on the latest release (upgrade + by running `python3 -m pip install --upgrade slither-analyzer`). + If you are having difficulty installing slither, please head over to the "Discussions" page. + Thanks for taking the time to fill out this bug report! type: markdown - @@ -17,7 +21,7 @@ body: required: true - attributes: - description: "It can be a github repo, etherscan link, or code snippet." + description: "It can be a github repo (preferred), etherscan link, or code snippet." label: "Code example to reproduce the issue:" placeholder: "`contract A {}`\n" id: reproduce @@ -27,7 +31,7 @@ body: - attributes: description: | - What version of slither are you running? + What version of slither are you running? Run `slither --version` label: "Version:" id: version From f3f4b2084c053c37099a4f56021aeeb5cd76d9c4 Mon Sep 17 00:00:00 2001 From: dm Date: Wed, 5 Jun 2024 16:37:48 +0200 Subject: [PATCH 03/40] Update tests/e2e/printers/test_printers.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- tests/e2e/printers/test_printers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/e2e/printers/test_printers.py b/tests/e2e/printers/test_printers.py index fc7a22378c..aa5d7f8a46 100644 --- a/tests/e2e/printers/test_printers.py +++ b/tests/e2e/printers/test_printers.py @@ -35,7 +35,6 @@ def test_inheritance_printer(solc_binary_path) -> None: assert counter["B -> A"] == 2 assert counter["C -> A"] == 1 - # Let also test the include/exclude interface behavior # Check that the interface is not included assert "MyInterfaceX" not in content From 900fda77c1fecb6d88404552b51886e29fbdd7b7 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Wed, 5 Jun 2024 18:20:30 -0500 Subject: [PATCH 04/40] fix: sort by impact --- slither/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/__main__.py b/slither/__main__.py index 886d392c0d..58d276e1d3 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -239,6 +239,7 @@ def choose_detectors( set(detectors_to_run), args.detectors_to_include, detectors ) + detectors_to_run = sorted(detectors_to_run, key=lambda x: x.IMPACT) return detectors_to_run @@ -255,7 +256,6 @@ def __include_detectors( else: raise ValueError(f"Error: {detector} is not a detector") - detectors_to_run = sorted(detectors_to_run, key=lambda x: x.IMPACT) return detectors_to_run From 2e6508f28b18d6a9c88ff5c2bae8961bc9169ed7 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Wed, 5 Jun 2024 18:20:48 -0500 Subject: [PATCH 05/40] fix: do not report libraries as dead code --- slither/detectors/functions/dead_code.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/slither/detectors/functions/dead_code.py b/slither/detectors/functions/dead_code.py index 98eb97ff7e..7a2c6dbc4d 100644 --- a/slither/detectors/functions/dead_code.py +++ b/slither/detectors/functions/dead_code.py @@ -71,9 +71,10 @@ def _detect(self) -> List[Output]: continue if isinstance(function, FunctionContract) and ( function.contract_declarer.is_from_dependency() + or function.contract_declarer.is_library ): continue - # Continue if the functon is not implemented because it means the contract is abstract + # Continue if the function is not implemented because it means the contract is abstract if not function.is_implemented: continue info: DETECTOR_INFO = [function, " is never used and should be removed\n"] From c3a5fb219beffe7e9043b8e64ecd66bcd397cc4e Mon Sep 17 00:00:00 2001 From: Alexis Date: Wed, 12 Jun 2024 10:58:55 +0200 Subject: [PATCH 06/40] Add tests to slither-mutate and fix some Python 3.8 compatibility issues. --- .../mutator/mutators/abstract_mutator.py | 8 +- slither/tools/mutator/utils/file_handling.py | 2 +- .../mutator/utils/testing_generated_mutant.py | 7 +- tests/tools/mutator/__init__.py | 0 .../test_data/test_source_unit/README.md | 66 ++++++++++ .../test_data/test_source_unit/foundry.toml | 7 + .../test_source_unit/script/Counter.s.sol | 12 ++ .../test_source_unit/src/Counter.sol | 14 ++ .../test_source_unit/test/Counter.t.sol | 24 ++++ tests/tools/mutator/test_mutator.py | 122 ++++++++++++++++++ 10 files changed, 256 insertions(+), 6 deletions(-) create mode 100644 tests/tools/mutator/__init__.py create mode 100644 tests/tools/mutator/test_data/test_source_unit/README.md create mode 100644 tests/tools/mutator/test_data/test_source_unit/foundry.toml create mode 100644 tests/tools/mutator/test_data/test_source_unit/script/Counter.s.sol create mode 100644 tests/tools/mutator/test_data/test_source_unit/src/Counter.sol create mode 100644 tests/tools/mutator/test_data/test_source_unit/test/Counter.t.sol create mode 100644 tests/tools/mutator/test_mutator.py diff --git a/slither/tools/mutator/mutators/abstract_mutator.py b/slither/tools/mutator/mutators/abstract_mutator.py index 69c77a4ca6..cb435f8569 100644 --- a/slither/tools/mutator/mutators/abstract_mutator.py +++ b/slither/tools/mutator/mutators/abstract_mutator.py @@ -1,7 +1,7 @@ import abc import logging from pathlib import Path -from typing import Optional, Dict, Tuple, List +from typing import Optional, Dict, Tuple, List, Union from slither.core.compilation_unit import SlitherCompilationUnit from slither.formatters.utils.patches import apply_patch, create_diff from slither.tools.mutator.utils.testing_generated_mutant import test_patch @@ -27,7 +27,7 @@ def __init__( # pylint: disable=too-many-arguments testing_command: str, testing_directory: str, contract_instance: Contract, - solc_remappings: str | None, + solc_remappings: Union[str, None], verbose: bool, very_verbose: bool, output_folder: Path, @@ -81,7 +81,7 @@ def mutate(self) -> Tuple[List[int], List[int], List[int]]: (all_patches) = self._mutate() if "patches" not in all_patches: logger.debug("No patches found by %s", self.NAME) - return ([0, 0, 0], [0, 0, 0], self.dont_mutate_line) + return [0, 0, 0], [0, 0, 0], self.dont_mutate_line for file in all_patches["patches"]: # Note: This should only loop over a single file original_txt = self.slither.source_code[file].encode("utf8") @@ -146,4 +146,4 @@ def mutate(self) -> Tuple[List[int], List[int], List[int]]: f"Found {self.uncaught_mutant_counts[2]} uncaught tweak mutants so far (out of {self.total_mutant_counts[2]} that compile)" ) - return (self.total_mutant_counts, self.uncaught_mutant_counts, self.dont_mutate_line) + return self.total_mutant_counts, self.uncaught_mutant_counts, self.dont_mutate_line diff --git a/slither/tools/mutator/utils/file_handling.py b/slither/tools/mutator/utils/file_handling.py index 7c02ce0992..81e30efc65 100644 --- a/slither/tools/mutator/utils/file_handling.py +++ b/slither/tools/mutator/utils/file_handling.py @@ -111,7 +111,7 @@ def get_sol_file_list(codebase: Path, ignore_paths: Union[List[str], None]) -> L # if input is folder if codebase.is_dir(): for file_name in codebase.rglob("*.sol"): - if not any(part in ignore_paths for part in file_name.parts): + if file_name.is_file() and not any(part in ignore_paths for part in file_name.parts): sol_file_list.append(file_name.as_posix()) return sol_file_list diff --git a/slither/tools/mutator/utils/testing_generated_mutant.py b/slither/tools/mutator/utils/testing_generated_mutant.py index 39e7d39de8..d62fc3ff0e 100644 --- a/slither/tools/mutator/utils/testing_generated_mutant.py +++ b/slither/tools/mutator/utils/testing_generated_mutant.py @@ -22,7 +22,12 @@ def compile_generated_mutant(file_path: str, mappings: str) -> bool: return False -def run_test_cmd(cmd: str, timeout: int | None, target_file: str | None, verbose: bool) -> bool: +def run_test_cmd( + cmd: str, + timeout: Union[int, None] = None, + target_file: Union[str, None] = None, + verbose: bool = False, +) -> bool: """ function to run codebase tests returns: boolean whether the tests passed or not diff --git a/tests/tools/mutator/__init__.py b/tests/tools/mutator/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/tools/mutator/test_data/test_source_unit/README.md b/tests/tools/mutator/test_data/test_source_unit/README.md new file mode 100644 index 0000000000..9265b45584 --- /dev/null +++ b/tests/tools/mutator/test_data/test_source_unit/README.md @@ -0,0 +1,66 @@ +## Foundry + +**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** + +Foundry consists of: + +- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). +- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. +- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. +- **Chisel**: Fast, utilitarian, and verbose solidity REPL. + +## Documentation + +https://book.getfoundry.sh/ + +## Usage + +### Build + +```shell +$ forge build +``` + +### Test + +```shell +$ forge test +``` + +### Format + +```shell +$ forge fmt +``` + +### Gas Snapshots + +```shell +$ forge snapshot +``` + +### Anvil + +```shell +$ anvil +``` + +### Deploy + +```shell +$ forge script script/Counter.s.sol:CounterScript --rpc-url --private-key +``` + +### Cast + +```shell +$ cast +``` + +### Help + +```shell +$ forge --help +$ anvil --help +$ cast --help +``` diff --git a/tests/tools/mutator/test_data/test_source_unit/foundry.toml b/tests/tools/mutator/test_data/test_source_unit/foundry.toml new file mode 100644 index 0000000000..908c595d02 --- /dev/null +++ b/tests/tools/mutator/test_data/test_source_unit/foundry.toml @@ -0,0 +1,7 @@ +[profile.default] +src = 'src' +out = 'out' +libs = ['lib'] +solc = "0.8.15" + +# See more config options https://github.com/foundry-rs/foundry/tree/master/config \ No newline at end of file diff --git a/tests/tools/mutator/test_data/test_source_unit/script/Counter.s.sol b/tests/tools/mutator/test_data/test_source_unit/script/Counter.s.sol new file mode 100644 index 0000000000..df9ee8b02c --- /dev/null +++ b/tests/tools/mutator/test_data/test_source_unit/script/Counter.s.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import {Script, console} from "forge-std/Script.sol"; + +contract CounterScript is Script { + function setUp() public {} + + function run() public { + vm.broadcast(); + } +} diff --git a/tests/tools/mutator/test_data/test_source_unit/src/Counter.sol b/tests/tools/mutator/test_data/test_source_unit/src/Counter.sol new file mode 100644 index 0000000000..7a83fefc42 --- /dev/null +++ b/tests/tools/mutator/test_data/test_source_unit/src/Counter.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.15; + +contract Counter { + uint256 public number; + + function setNumber(uint256 newNumber) public { + number = newNumber; + } + + function increment() public { + number++; + } +} diff --git a/tests/tools/mutator/test_data/test_source_unit/test/Counter.t.sol b/tests/tools/mutator/test_data/test_source_unit/test/Counter.t.sol new file mode 100644 index 0000000000..6178bf4d2f --- /dev/null +++ b/tests/tools/mutator/test_data/test_source_unit/test/Counter.t.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.15; + +import {Test, console} from "forge-std/Test.sol"; +import {Counter} from "../src/Counter.sol"; + +contract CounterTest is Test { + Counter public counter; + + function setUp() public { + counter = new Counter(); + counter.setNumber(0); + } + + function test_Increment() public { + counter.increment(); + assertEq(counter.number(), 1); + } + + function testFuzz_SetNumber(uint256 x) public { + counter.setNumber(x); + assertEq(counter.number(), x); + } +} diff --git a/tests/tools/mutator/test_mutator.py b/tests/tools/mutator/test_mutator.py new file mode 100644 index 0000000000..82ed0541e0 --- /dev/null +++ b/tests/tools/mutator/test_mutator.py @@ -0,0 +1,122 @@ +import os +import subprocess +import tempfile +from pathlib import Path +from unittest import mock +import argparse +from contextlib import contextmanager + +import pytest +from slither import Slither +from slither.tools.mutator.__main__ import _get_mutators, main +from slither.tools.mutator.utils.testing_generated_mutant import run_test_cmd +from slither.tools.mutator.utils.file_handling import get_sol_file_list, backup_source_file + + +TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" + + +@contextmanager +def change_directory(new_dir): + original_dir = os.getcwd() + os.chdir(new_dir) + try: + yield + finally: + os.chdir(original_dir) + + +def test_get_mutators(): + + mutators = _get_mutators(None) + assert mutators + + mutators = _get_mutators(["ASOR"]) + assert len(mutators) == 1 + assert mutators[0].NAME == "ASOR" + + mutators = _get_mutators(["ASOR", "NotExisiting"]) + assert len(mutators) == 1 + + +@mock.patch( + "argparse.ArgumentParser.parse_args", + return_value=argparse.Namespace( + test_cmd="forge test", + test_dir=None, + ignore_dirs="lib,mutation_campaign", + output_dir=None, + timeout=None, + solc_remaps="forge-std=./lib/forge-std", + verbose=None, + very_verbose=None, + mutators_to_run=None, + comprehensive=None, + codebase=(TEST_DATA_DIR / "test_source_unit" / "src" / "Counter.sol").as_posix(), + contract_names="Counter", + ), +) +@pytest.mark.skip(reason="Slow test") +def test_mutator(mock_args): # pylint: disable=unused-argument + + with change_directory(TEST_DATA_DIR / "test_source_unit"): + main() + + +def test_backup_source_file(): + + file_path = (TEST_DATA_DIR / "test_source_unit" / "src" / "Counter.sol").as_posix() + sl = Slither(file_path) + + with tempfile.TemporaryDirectory() as directory: + files_dict = backup_source_file(sl.source_code, Path(directory)) + + assert len(files_dict) == 1 + assert Path(files_dict[file_path]).exists() + + +def test_get_sol_file_list(): + + project_directory = TEST_DATA_DIR / "test_source_unit" + + files = get_sol_file_list(project_directory, None) + + assert len(files) == 46 + + files = get_sol_file_list(project_directory, ["lib"]) + assert len(files) == 3 + + files = get_sol_file_list(project_directory, ["lib", "script"]) + assert len(files) == 2 + + files = get_sol_file_list(project_directory / "src" / "Counter.sol", None) + assert len(files) == 1 + + (project_directory / "test.sol").mkdir() + files = get_sol_file_list(project_directory, None) + assert all("test.sol" not in file for file in files) + (project_directory / "test.sol").rmdir() + + +def test_run_test(caplog): + with change_directory(TEST_DATA_DIR / "test_source_unit"): + result = run_test_cmd("forge test", timeout=None, target_file=None, verbose=True) + assert result + assert not caplog.records + + # Failed command + result = run_test_cmd("forge non-test", timeout=None, target_file=None, verbose=True) + assert not result + assert caplog.records + + +def test_run_tests_timeout(caplog, monkeypatch): + def mock_run(*args, **kwargs): + raise subprocess.TimeoutExpired(cmd=args[0], timeout=kwargs.get("timeout")) + + monkeypatch.setattr(subprocess, "run", mock_run) + + with change_directory(TEST_DATA_DIR / "test_source_unit"): + result = run_test_cmd("forge test", timeout=1) + assert not result + assert "Tests took too long" in caplog.messages[0] From 7b983e3fc537762cda3233b91ce2cc6321d1c6ff Mon Sep 17 00:00:00 2001 From: Alexis Date: Wed, 12 Jun 2024 11:14:09 +0200 Subject: [PATCH 07/40] Fix typo (thanks Gustavo) --- slither/tools/mutator/mutators/LIR.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slither/tools/mutator/mutators/LIR.py b/slither/tools/mutator/mutators/LIR.py index cc58cbae16..fc621829fa 100644 --- a/slither/tools/mutator/mutators/LIR.py +++ b/slither/tools/mutator/mutators/LIR.py @@ -31,7 +31,7 @@ def _mutate(self) -> Dict: # pylint: disable=too-many-branches literal_replacements.append(variable.type.max) # append data type max value if str(variable.type).startswith("uint"): literal_replacements.append("1") - elif str(variable.type).startswith("uint"): + elif str(variable.type).startswith("int"): literal_replacements.append("-1") # Get the string start = variable.source_mapping.start @@ -63,7 +63,7 @@ def _mutate(self) -> Dict: # pylint: disable=too-many-branches literal_replacements.append(variable.type.max) if str(variable.type).startswith("uint"): literal_replacements.append("1") - elif str(variable.type).startswith("uint"): + elif str(variable.type).startswith("int"): literal_replacements.append("-1") start = variable.source_mapping.start stop = start + variable.source_mapping.length From f1df3ea7534f9c7ef36a8afee618f62e95ce0c2f Mon Sep 17 00:00:00 2001 From: Alexis Date: Wed, 12 Jun 2024 11:20:36 +0200 Subject: [PATCH 08/40] Run tests only if forge is available. --- .../test_data/test_source_unit/README.md | 65 +------------------ tests/tools/mutator/test_mutator.py | 16 ++++- 2 files changed, 16 insertions(+), 65 deletions(-) diff --git a/tests/tools/mutator/test_data/test_source_unit/README.md b/tests/tools/mutator/test_data/test_source_unit/README.md index 9265b45584..554472962d 100644 --- a/tests/tools/mutator/test_data/test_source_unit/README.md +++ b/tests/tools/mutator/test_data/test_source_unit/README.md @@ -1,66 +1,7 @@ -## Foundry +# Counter -**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** - -Foundry consists of: - -- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). -- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. -- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. -- **Chisel**: Fast, utilitarian, and verbose solidity REPL. - -## Documentation - -https://book.getfoundry.sh/ - -## Usage - -### Build - -```shell -$ forge build -``` - -### Test - -```shell -$ forge test -``` - -### Format - -```shell -$ forge fmt -``` - -### Gas Snapshots - -```shell -$ forge snapshot -``` - -### Anvil - -```shell -$ anvil -``` - -### Deploy - -```shell -$ forge script script/Counter.s.sol:CounterScript --rpc-url --private-key -``` - -### Cast - -```shell -$ cast -``` - -### Help +Init using : ```shell -$ forge --help -$ anvil --help -$ cast --help +forge install --no-commit --no-git . ``` diff --git a/tests/tools/mutator/test_mutator.py b/tests/tools/mutator/test_mutator.py index 82ed0541e0..fbfe86b9ac 100644 --- a/tests/tools/mutator/test_mutator.py +++ b/tests/tools/mutator/test_mutator.py @@ -1,10 +1,11 @@ +import argparse +from contextlib import contextmanager import os +from pathlib import Path +import shutil import subprocess import tempfile -from pathlib import Path from unittest import mock -import argparse -from contextlib import contextmanager import pytest from slither import Slither @@ -15,6 +16,9 @@ TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" +foundry_available = shutil.which("forge") is not None +project_ready = Path(TEST_DATA_DIR, "test_source_unit/lib/forge-std").exists() + @contextmanager def change_directory(new_dir): @@ -75,6 +79,9 @@ def test_backup_source_file(): assert Path(files_dict[file_path]).exists() +@pytest.mark.skipif( + not foundry_available or not project_ready, reason="requires Foundry and project setup" +) def test_get_sol_file_list(): project_directory = TEST_DATA_DIR / "test_source_unit" @@ -98,6 +105,9 @@ def test_get_sol_file_list(): (project_directory / "test.sol").rmdir() +@pytest.mark.skipif( + not foundry_available or not project_ready, reason="requires Foundry and project setup" +) def test_run_test(caplog): with change_directory(TEST_DATA_DIR / "test_source_unit"): result = run_test_cmd("forge test", timeout=None, target_file=None, verbose=True) From 94fc82cc74c78ef4ffc9910126b8a5aac22ef7bb Mon Sep 17 00:00:00 2001 From: Alexis Date: Wed, 12 Jun 2024 11:28:18 +0200 Subject: [PATCH 09/40] Run tools tests in CI. --- .github/scripts/tool_test_runner.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/scripts/tool_test_runner.sh b/.github/scripts/tool_test_runner.sh index 30d8176a0e..574358e106 100755 --- a/.github/scripts/tool_test_runner.sh +++ b/.github/scripts/tool_test_runner.sh @@ -2,11 +2,11 @@ # used to pass --cov=$path and --cov-append to pytest if [ "$1" != "" ]; then - pytest "$1" tests/tools/read-storage/test_read_storage.py + pytest "$1" tests/tools status_code=$? python -m coverage report else - pytest tests/tools/read-storage/test_read_storage.py + pytest tests/tools status_code=$? fi From 43301c750d27363a56f370dd0e6dc5a5b84b5c35 Mon Sep 17 00:00:00 2001 From: Alexis Date: Wed, 12 Jun 2024 14:26:40 +0200 Subject: [PATCH 10/40] Remove last wrongly typed annotation --- slither/tools/mutator/__main__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slither/tools/mutator/__main__.py b/slither/tools/mutator/__main__.py index 8a7ce3e1ab..dea11676a6 100644 --- a/slither/tools/mutator/__main__.py +++ b/slither/tools/mutator/__main__.py @@ -6,7 +6,7 @@ import sys import time from pathlib import Path -from typing import Type, List, Any, Optional +from typing import Type, List, Any, Optional, Union from crytic_compile import cryticparser from slither import Slither from slither.tools.mutator.utils.testing_generated_mutant import run_test_cmd @@ -116,7 +116,7 @@ def parse_args() -> argparse.Namespace: return parser.parse_args() -def _get_mutators(mutators_list: List[str] | None) -> List[Type[AbstractMutator]]: +def _get_mutators(mutators_list: Union[List[str], None]) -> List[Type[AbstractMutator]]: detectors_ = [getattr(all_mutators, name) for name in dir(all_mutators)] if mutators_list is not None: detectors = [ From 5c0eccfbc54f529c57863a3ea8dc894972d6d4bf Mon Sep 17 00:00:00 2001 From: Alexis Date: Wed, 12 Jun 2024 15:17:00 +0200 Subject: [PATCH 11/40] Fix test in CI. --- tests/tools/mutator/test_mutator.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/tools/mutator/test_mutator.py b/tests/tools/mutator/test_mutator.py index fbfe86b9ac..68b595319c 100644 --- a/tests/tools/mutator/test_mutator.py +++ b/tests/tools/mutator/test_mutator.py @@ -61,16 +61,17 @@ def test_get_mutators(): ), ) @pytest.mark.skip(reason="Slow test") -def test_mutator(mock_args): # pylint: disable=unused-argument +def test_mutator(mock_args, solc_binary_path): # pylint: disable=unused-argument with change_directory(TEST_DATA_DIR / "test_source_unit"): main() -def test_backup_source_file(): +def test_backup_source_file(solc_binary_path): + solc_path = solc_binary_path("0.8.15") file_path = (TEST_DATA_DIR / "test_source_unit" / "src" / "Counter.sol").as_posix() - sl = Slither(file_path) + sl = Slither(file_path, solc=solc_path) with tempfile.TemporaryDirectory() as directory: files_dict = backup_source_file(sl.source_code, Path(directory)) From 48fc49a4bec59a81a50f3e05c6a723e797efaeaf Mon Sep 17 00:00:00 2001 From: Simone Date: Fri, 14 Jun 2024 12:03:32 +0200 Subject: [PATCH 12/40] Fix for dynamic array operations --- slither/tools/mutator/mutators/AOR.py | 39 ++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/slither/tools/mutator/mutators/AOR.py b/slither/tools/mutator/mutators/AOR.py index 0bf0fb2a29..f86e7d3d4a 100644 --- a/slither/tools/mutator/mutators/AOR.py +++ b/slither/tools/mutator/mutators/AOR.py @@ -2,7 +2,12 @@ from slither.slithir.operations import Binary, BinaryType from slither.tools.mutator.utils.patch import create_patch_with_line from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator +from slither.core.variables.variable import Variable from slither.core.expressions.unary_operation import UnaryOperation +from slither.core.expressions.call_expression import CallExpression +from slither.core.expressions.member_access import MemberAccess +from slither.core.expressions.identifier import Identifier +from slither.core.solidity_types.array_type import ArrayType arithmetic_operators = [ BinaryType.ADDITION, @@ -27,7 +32,39 @@ def _mutate(self) -> Dict: ir_expression = node.expression except: # pylint: disable=bare-except continue - for ir in node.irs: + + # Special cases handling .push and .pop on dynamic arrays. + # The IR for these operations has a binary operation due to internal conversion + # (see convert_to_push and convert_to_pop in slithir/convert.py) + # however it's not present in the source code and should not be mutated. + # pylint: disable=too-many-boolean-expressions + if ( + isinstance(ir_expression, CallExpression) + and isinstance(ir_expression.called, MemberAccess) + and ir_expression.called.member_name == "pop" + and isinstance(ir_expression.called.expression, Identifier) + and isinstance(ir_expression.called.expression.value, Variable) + and isinstance(ir_expression.called.expression.value.type, ArrayType) + ): + continue + + # For a .push instruction we skip the last 6 IR operations + # because they are fixed based on the internal conversion to the IR + # while we need to look at the preceding instructions because + # they might contain Binary IR to be mutated. + # For example for a.push(3+x) it's correct to mutate 3+x. + irs = ( + node.irs[:-6] + if isinstance(ir_expression, CallExpression) + and isinstance(ir_expression.called, MemberAccess) + and ir_expression.called.member_name == "push" + and isinstance(ir_expression.called.expression, Identifier) + and isinstance(ir_expression.called.expression.value, Variable) + and isinstance(ir_expression.called.expression.value.type, ArrayType) + else node.irs + ) + + for ir in irs: if isinstance(ir, Binary) and ir.type in arithmetic_operators: if isinstance(ir_expression, UnaryOperation): continue From eb2076556deea38f5e1e34cc22104410cfb0cf76 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 22:20:46 +0000 Subject: [PATCH 13/40] Bump pypa/gh-action-pypi-publish from 1.8.14 to 1.9.0 Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.8.14 to 1.9.0. - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.8.14...v1.9.0) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 031d1a376d..c5ec555ceb 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -44,7 +44,7 @@ jobs: path: dist/ - name: publish - uses: pypa/gh-action-pypi-publish@v1.8.14 + uses: pypa/gh-action-pypi-publish@v1.9.0 - name: sign uses: sigstore/gh-action-sigstore-python@v2.1.1 From 6495148a6e03cdf026be83402674305b82702c12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 22:20:49 +0000 Subject: [PATCH 14/40] Bump docker/build-push-action from 5 to 6 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v5...v6) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 29f0ac2e02..b039f69d97 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -47,7 +47,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Docker Build and Push - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: platforms: linux/amd64,linux/arm64/v8,linux/arm/v7 target: final From 469286fa99e7c73b6551ad0169e8351b31ff997e Mon Sep 17 00:00:00 2001 From: Simone Date: Fri, 21 Jun 2024 10:51:56 +0200 Subject: [PATCH 15/40] Don't report if destination is immutable state var --- .../detectors/functions/arbitrary_send_eth.py | 3 +++ ...ndEth_0_6_11_arbitrary_send_eth_sol__0.txt | 8 ++++---- ...endEth_0_7_6_arbitrary_send_eth_sol__0.txt | 8 ++++---- .../0.6.11/arbitrary_send_eth.sol | 7 ++++++- .../0.6.11/arbitrary_send_eth.sol-0.6.11.zip | Bin 3698 -> 4147 bytes .../0.7.6/arbitrary_send_eth.sol | 7 ++++++- .../0.7.6/arbitrary_send_eth.sol-0.7.6.zip | Bin 3610 -> 4052 bytes 7 files changed, 23 insertions(+), 10 deletions(-) diff --git a/slither/detectors/functions/arbitrary_send_eth.py b/slither/detectors/functions/arbitrary_send_eth.py index f6c688a3fc..56fb112500 100644 --- a/slither/detectors/functions/arbitrary_send_eth.py +++ b/slither/detectors/functions/arbitrary_send_eth.py @@ -30,6 +30,7 @@ SolidityCall, Transfer, ) +from slither.core.variables.state_variable import StateVariable # pylint: disable=too-many-nested-blocks,too-many-branches from slither.utils.output import Output @@ -67,6 +68,8 @@ def arbitrary_send(func: Function) -> Union[bool, List[Node]]: continue if ir.call_value == SolidityVariableComposed("msg.value"): continue + if isinstance(ir.destination, StateVariable) and ir.destination.is_immutable: + continue if is_dependent( ir.call_value, SolidityVariableComposed("msg.value"), diff --git a/tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_6_11_arbitrary_send_eth_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_6_11_arbitrary_send_eth_sol__0.txt index 56ccf3cd3a..d2a1a487f2 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_6_11_arbitrary_send_eth_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_6_11_arbitrary_send_eth_sol__0.txt @@ -1,8 +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 +Test.direct() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#16-18) 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) + - msg.sender.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#17) -Test.direct() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#11-13) sends eth to arbitrary user +Test.indirect() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#24-26) 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) + - destination.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#25) diff --git a/tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_7_6_arbitrary_send_eth_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_7_6_arbitrary_send_eth_sol__0.txt index 3d4a4f0377..5d93561260 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_7_6_arbitrary_send_eth_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_7_6_arbitrary_send_eth_sol__0.txt @@ -1,8 +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 +Test.direct() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#16-18) 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) + - msg.sender.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#17) -Test.indirect() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#19-21) sends eth to arbitrary user +Test.indirect() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#24-26) 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) + - destination.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#25) diff --git a/tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol b/tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol index 9a0c743c48..d494d0e08f 100644 --- a/tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol +++ b/tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol @@ -1,13 +1,18 @@ contract Test{ address payable destination; - + address payable immutable destination_imm; mapping (address => uint) balances; constructor() public{ + destination_imm = payable(msg.sender); balances[msg.sender] = 0; } + function send_immutable() public{ + destination_imm.send(address(this).balance); + } + function direct() public{ msg.sender.send(address(this).balance); } diff --git a/tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol-0.6.11.zip b/tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol-0.6.11.zip index ebbb8c3463edc4b4a78616f9fe1be05d27b62ee5..bec986a858d51d4dd1da8672bd35cebc8ae9413f 100644 GIT binary patch delta 4031 zcmV;w4?ytp9J3%BP)h>@KL7#%4gj}R)mYms9zuN&005ks001hJFAgn{NGgBzLq3k% z8(|US<+$<-R-TXbNE-97FH-K9mq@1&+0=A#oo)!e&BRa?>@UL&m{xMKPC59HR20S% z5ODwq5A%Q*MB%C(?OqWlHvD&PN0tm4XZ!~VsZvFV7wRmWI*{u2h|qdD*?x`p#+r^A z$&qu;hpC*Q?uBrPUj5xI>Oz0dX-88uB1!EVkTFr5R2R@^8Px{$EaLQnF}R7Kh29x7 zLgqwITHCc#NjuD&IqSFW+NipdgUMAvI(BC6`Dzomfu_ee`^NgLwRLS6BF)nTkX(wd zY#VfAA2Ip;rv-5p3_#CZv9zG3FeB#B_|gT`B^VF~^_~ZllA?kqIb(k|h5%}7FY&cU zaz}pG63e&D0~?DifMZREy=gn@h0n7@Q_rWo!4e|~cD~ko()!*%>lKk${JM$;n9OIe z`EGS`8)5O-#fz^FbI;CwzKeB?wp(2}28gle=Q zKd4msp&}o63TuDJolyn~uYk5k={_rl)Y8p{QqnyQStZ<<40EjV?pvuc1vK4F-WFtd z_*fF>6EFTD1Fnx(r7CsogCkJ9*>X~gDmeZ?{oLyv*Etf%_WO;b)ALp5?H(CvwH{+e zqTI)FbDdMwe(3?C-!%aY4FX{xXLV}g`qyW7UljNkjLLr_O*9U_9ewSBmyWWJ3-NTJ zwHKLEmhP6~xo)o~az6dD0-inUqZTQhP8r+Hpwb(`U;dhc4A{)S(K<&C6K5w4N!Z0Q zThV@_DhgraATgbIRzWmwZ#0;0%K1vgUwu1m9J&Pf4jgUx|ET6Dcg9UJ28`X8=p1`V zgb<9hOksa5^PX~;yCbE+tgUpmPnow90cHL%tazTGCh!1hJ*9ONqOA}s;hZvsZ-5wS zX;3;Ijn5E9?UhDx^dQZi%|Sq$D∓&^CqfeTJOC)F@#paT`Y-utc5}DmKPR-2sjF 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 delta 3578 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 uint) balances; constructor() public{ + destination_imm = payable(msg.sender); balances[msg.sender] = 0; } + function send_immutable() public{ + destination_imm.send(address(this).balance); + } + function direct() public{ msg.sender.send(address(this).balance); } diff --git a/tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol-0.7.6.zip b/tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol-0.7.6.zip index 3bd2416f58c603b01349fc84d0af1d54fca92d8d..e84aca40ef51edb58097c3db2b84f53590b352c4 100644 GIT binary patch delta 3928 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 delta 3489 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 Pc9Vb)P6n(E00000@vNX> From ee7687501d19ea72019564f6457f0752d2a51867 Mon Sep 17 00:00:00 2001 From: Thomas Heim <106417552+ThomasHeim11@users.noreply.github.com> Date: Sat, 22 Jun 2024 17:18:18 +0200 Subject: [PATCH 16/40] update WIKI_DESCRIPTION --- slither/detectors/functions/dead_code.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/detectors/functions/dead_code.py b/slither/detectors/functions/dead_code.py index 7a2c6dbc4d..5cafa16504 100644 --- a/slither/detectors/functions/dead_code.py +++ b/slither/detectors/functions/dead_code.py @@ -25,7 +25,7 @@ class DeadCode(AbstractDetector): WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#dead-code" WIKI_TITLE = "Dead-code" - WIKI_DESCRIPTION = "Functions that are not sued." + WIKI_DESCRIPTION = "Functions that are not used." # region wiki_exploit_scenario WIKI_EXPLOIT_SCENARIO = """ From 072a64bc99c5068b42358854f55f7f31469f752c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Mon, 24 Jun 2024 09:05:39 -0700 Subject: [PATCH 17/40] Dockerfile: fix `ckzg` build Building `ckzg` requires `make` to be present. --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 6de5ec2c66..c65efc22e3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:jammy AS python-wheels RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ gcc \ git \ + make \ python3-dev \ python3-pip \ && rm -rf /var/lib/apt/lists/* From 95e153d6ba2aea84ad6fffd17a90ba5d745cfab5 Mon Sep 17 00:00:00 2001 From: Mukul Kolpe Date: Thu, 27 Jun 2024 08:07:38 +0530 Subject: [PATCH 18/40] Added length check on bugs_by_version for specific version_number --- slither/detectors/attributes/incorrect_solc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/detectors/attributes/incorrect_solc.py b/slither/detectors/attributes/incorrect_solc.py index 532a964934..e60412cef4 100644 --- a/slither/detectors/attributes/incorrect_solc.py +++ b/slither/detectors/attributes/incorrect_solc.py @@ -71,7 +71,7 @@ def _check_version(self, version: Tuple[str, str, str, str, str]) -> Optional[st if op and op not in [">", ">=", "^"]: return self.LESS_THAN_TXT version_number = ".".join(version[2:]) - if version_number in bugs_by_version: + if version_number in bugs_by_version and len(bugs_by_version[version_number]): bugs = "\n".join([f"\t- {bug}" for bug in bugs_by_version[version_number]]) return self.BUGGY_VERSION_TXT + f"\n{bugs}" return None From bacd8c0222af135e43b91f3c8dd564b8e6cdf416 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Fri, 28 Jun 2024 11:14:41 +0200 Subject: [PATCH 19/40] Update FUNDING.json --- FUNDING.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/FUNDING.json b/FUNDING.json index bbda1e452d..5caad61f5b 100644 --- a/FUNDING.json +++ b/FUNDING.json @@ -4,4 +4,9 @@ "ownedBy": "0xc44F30Be3eBBEfdDBB5a85168710b4f0e18f4Ff0" } } + "drips": { + "ethereum": { + "ownedBy": "0x5e2BA02F62bD4efa939e3B80955bBC21d015DbA0" + } + } } From 9a5b4f5cff9db6475c5badff18f9882180d5f344 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Fri, 28 Jun 2024 11:15:05 +0200 Subject: [PATCH 20/40] Update FUNDING.json --- FUNDING.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FUNDING.json b/FUNDING.json index 5caad61f5b..189cf2f950 100644 --- a/FUNDING.json +++ b/FUNDING.json @@ -3,7 +3,7 @@ "op-mainnet": { "ownedBy": "0xc44F30Be3eBBEfdDBB5a85168710b4f0e18f4Ff0" } - } + }, "drips": { "ethereum": { "ownedBy": "0x5e2BA02F62bD4efa939e3B80955bBC21d015DbA0" From a22ae18171e54d7396a1b1cf5718c1506ad6a6e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 22:26:17 +0000 Subject: [PATCH 21/40] Bump sigstore/gh-action-sigstore-python from 2.1.1 to 3.0.0 Bumps [sigstore/gh-action-sigstore-python](https://github.com/sigstore/gh-action-sigstore-python) from 2.1.1 to 3.0.0. - [Release notes](https://github.com/sigstore/gh-action-sigstore-python/releases) - [Changelog](https://github.com/sigstore/gh-action-sigstore-python/blob/main/CHANGELOG.md) - [Commits](https://github.com/sigstore/gh-action-sigstore-python/compare/v2.1.1...v3.0.0) --- updated-dependencies: - dependency-name: sigstore/gh-action-sigstore-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c5ec555ceb..0a0f04f2bc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -47,7 +47,7 @@ jobs: uses: pypa/gh-action-pypi-publish@v1.9.0 - name: sign - uses: sigstore/gh-action-sigstore-python@v2.1.1 + uses: sigstore/gh-action-sigstore-python@v3.0.0 with: inputs: ./dist/*.tar.gz ./dist/*.whl release-signing-artifacts: true From 48815192f25d9ab8916393a57d2b6d98e3b067e6 Mon Sep 17 00:00:00 2001 From: dm Date: Thu, 18 Jul 2024 16:59:02 +0200 Subject: [PATCH 22/40] feat: make tables fit within terminal by default (#2426) This PR adds a `max_width` parameter to MyPrettyTable to restrict the maximum width of its underlying table. The value can be an integer, "max" (detect automatically the correct width) or None (no width limit) * Add a new parameter `max_width` to MyPrettyTable to enhance its display for CLI usage * Fix the description of the Loc printer, and adjust the maximal width. * bump prettytable * default all prettytable's to fit within max terminal width --------- Co-authored-by: alpharush <0xalpharush@protonmail.com> --- setup.py | 2 +- slither/printers/summary/loc.py | 4 ++-- slither/utils/command_line.py | 4 +++- slither/utils/myprettytable.py | 26 ++++++++++++++++++++++---- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index a669b82a30..3b361d6058 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ python_requires=">=3.8", install_requires=[ "packaging", - "prettytable>=3.3.0", + "prettytable>=3.10.2", "pycryptodome>=3.4.6", "crytic-compile>=0.3.7,<0.4.0", # "crytic-compile@git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile", diff --git a/slither/printers/summary/loc.py b/slither/printers/summary/loc.py index 35bb20fc4b..886803e8e2 100644 --- a/slither/printers/summary/loc.py +++ b/slither/printers/summary/loc.py @@ -17,8 +17,8 @@ class LocPrinter(AbstractPrinter): ARGUMENT = "loc" - HELP = """Count the total number lines of code (LOC), source lines of code (SLOC), \ - and comment lines of code (CLOC) found in source files (SRC), dependencies (DEP), \ + HELP = """Count the total number lines of code (LOC), source lines of code (SLOC), + and comment lines of code (CLOC) found in source files (SRC), dependencies (DEP), and test files (TEST).""" WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#loc" diff --git a/slither/utils/command_line.py b/slither/utils/command_line.py index f5b9ab4527..b8888cb85b 100644 --- a/slither/utils/command_line.py +++ b/slither/utils/command_line.py @@ -360,8 +360,10 @@ def output_printers(printer_classes: List[Type[AbstractPrinter]]) -> None: printers_list = sorted(printers_list, key=lambda element: (element[0])) idx = 1 for (argument, help_info) in printers_list: - table.add_row([str(idx), argument, help_info]) + # Clean multi line HELP info + table.add_row([str(idx), argument, " ".join(x.strip() for x in help_info.splitlines())]) idx = idx + 1 + print(table) diff --git a/slither/utils/myprettytable.py b/slither/utils/myprettytable.py index b33fb9c5f7..ac666a5014 100644 --- a/slither/utils/myprettytable.py +++ b/slither/utils/myprettytable.py @@ -1,3 +1,4 @@ +from shutil import get_terminal_size from typing import List, Dict, Union from prettytable import PrettyTable @@ -7,7 +8,12 @@ class MyPrettyTable: - def __init__(self, field_names: List[str], pretty_align: bool = True): # TODO: True by default? + def __init__( + self, + field_names: List[str], + pretty_align: bool = True, + max_width: Union[int, None] = "max", # Default value is "max" + ): self._field_names = field_names self._rows: List = [] self._options: Dict = {} @@ -19,6 +25,17 @@ def __init__(self, field_names: List[str], pretty_align: bool = True): # TODO: else: self._options["set_alignment"] = [] + self.max_width = None + if max_width == "max": + # We use (0,0) as a fallback to detect if we are not attached to a terminal + # In this case, we fall back to the default behavior (i.e. printing as much as possible) + terminal_column = get_terminal_size((0, 0)).columns + if terminal_column != 0: + # We reduce slightly the max-width to take into account inconsistencies in terminals + self.max_width = terminal_column - 3 + else: + self.max_width = max_width + def add_row(self, row: List[Union[str, List[str]]]) -> None: self._rows.append(row) @@ -28,6 +45,9 @@ def to_pretty_table(self) -> PrettyTable: else: table = PrettyTable(self._field_names) + if self.max_width is not None: + table.max_table_width = self.max_width + for row in self._rows: table.add_row(row) if len(self._options["set_alignment"]): @@ -63,7 +83,5 @@ def make_pretty_table( table_row = [row] + [body[row][key] for key in headers[1:]] table.add_row(table_row) if totals: - table.add_row( - [total_header] + [sum([body[row][key] for row in body]) for key in headers[1:]] - ) + table.add_row([total_header] + [sum(body[row][key] for row in body) for key in headers[1:]]) return table From fda26fa865f33c6bab66a4257bc17ce4ff87e7b2 Mon Sep 17 00:00:00 2001 From: Daniel Bast <2790401+dbast@users.noreply.github.com> Date: Fri, 2 Aug 2024 19:18:21 +0200 Subject: [PATCH 23/40] Enable running slither as pre-commit hook --- .pre-commit-hooks.yaml | 7 +++++++ README.md | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 .pre-commit-hooks.yaml diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml new file mode 100644 index 0000000000..0f1b2fbeed --- /dev/null +++ b/.pre-commit-hooks.yaml @@ -0,0 +1,7 @@ +- id: slither + name: Slither + description: Run Slither on your project + entry: slither . + pass_filenames: false + language: python + files: \.sol$ diff --git a/README.md b/README.md index 515d6a9f7d..5dc7de20f1 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,13 @@ docker run -it -v /home/share:/share trailofbits/eth-security-toolbox ### Integration * For GitHub action integration, use [slither-action](https://github.com/marketplace/actions/slither-action). +* For pre-commit integratio, use (replace `$GIT_TAG` with real tag) + ``` + - repo: https://github.com/crytic/slither + rev: $GIT_TAG + hooks: + - slither + ``` * To generate a Markdown report, use `slither [target] --checklist`. * To generate a Markdown with GitHub source code highlighting, use `slither [target] --checklist --markdown-root https://github.com/ORG/REPO/blob/COMMIT/` (replace `ORG`, `REPO`, `COMMIT`) From f008437703aca24f4437dee458929c130e7d2cce Mon Sep 17 00:00:00 2001 From: Daniel Bast <2790401+dbast@users.noreply.github.com> Date: Fri, 2 Aug 2024 20:58:22 +0200 Subject: [PATCH 24/40] Specify language for code block in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5dc7de20f1..c7a466f808 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ docker run -it -v /home/share:/share trailofbits/eth-security-toolbox * For GitHub action integration, use [slither-action](https://github.com/marketplace/actions/slither-action). * For pre-commit integratio, use (replace `$GIT_TAG` with real tag) - ``` + ```YAML - repo: https://github.com/crytic/slither rev: $GIT_TAG hooks: From ee59976d68bb5ecc8cc352c4956a69c249280c23 Mon Sep 17 00:00:00 2001 From: Daniel Bast <2790401+dbast@users.noreply.github.com> Date: Sun, 11 Aug 2024 08:18:40 +0200 Subject: [PATCH 25/40] Specify folder via args to be easier to overwrite/configure --- .pre-commit-hooks.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 0f1b2fbeed..d561ca4297 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -1,7 +1,9 @@ - id: slither name: Slither description: Run Slither on your project - entry: slither . + entry: slither + args: + - . pass_filenames: false language: python files: \.sol$ From 4701885b24bcef1272ccbcc8b7593e26f86c3df4 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Mon, 12 Aug 2024 07:46:50 -0500 Subject: [PATCH 26/40] Revert "Reduce verbosity for InvalidCompilation errors" --- slither/__main__.py | 10 ++-------- tests/e2e/test_cli.py | 20 -------------------- 2 files changed, 2 insertions(+), 28 deletions(-) delete mode 100644 tests/e2e/test_cli.py diff --git a/slither/__main__.py b/slither/__main__.py index 58d276e1d3..633ad68cf3 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -14,7 +14,7 @@ from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union -from crytic_compile import cryticparser, CryticCompile, InvalidCompilation +from crytic_compile import cryticparser, CryticCompile from crytic_compile.platform.standard import generate_standard_export from crytic_compile.platform.etherscan import SUPPORTED_NETWORK from crytic_compile import compile_all, is_supported @@ -93,13 +93,7 @@ def process_all( detector_classes: List[Type[AbstractDetector]], printer_classes: List[Type[AbstractPrinter]], ) -> Tuple[List[Slither], List[Dict], List[Output], int]: - - try: - compilations = compile_all(target, **vars(args)) - except InvalidCompilation: - logger.error("Unable to compile all targets.") - sys.exit(2) - + compilations = compile_all(target, **vars(args)) slither_instances = [] results_detectors = [] results_printers = [] diff --git a/tests/e2e/test_cli.py b/tests/e2e/test_cli.py deleted file mode 100644 index 72e0441d6a..0000000000 --- a/tests/e2e/test_cli.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys -import tempfile -import pytest - -from slither.__main__ import main_impl - - -def test_cli_exit_on_invalid_compilation_file(caplog): - - with tempfile.NamedTemporaryFile("w") as f: - f.write("pragma solidity ^0.10000.0;") - - sys.argv = ["slither", f.name] - with pytest.raises(SystemExit) as pytest_wrapped_e: - main_impl([], []) - - assert pytest_wrapped_e.type == SystemExit - assert pytest_wrapped_e.value.code == 2 - - assert caplog.record_tuples[0] == ("Slither", 40, "Unable to compile all targets.") From 177fd1a02edce46b4416958851aa8d0ae9848301 Mon Sep 17 00:00:00 2001 From: Daniel Bast <2790401+dbast@users.noreply.github.com> Date: Tue, 13 Aug 2024 17:33:23 +0200 Subject: [PATCH 27/40] README.md aktualisieren MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Emilio López <2642849+elopez@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c7a466f808..a85d853699 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ docker run -it -v /home/share:/share trailofbits/eth-security-toolbox ### Integration * For GitHub action integration, use [slither-action](https://github.com/marketplace/actions/slither-action). -* For pre-commit integratio, use (replace `$GIT_TAG` with real tag) +* For pre-commit integration, use (replace `$GIT_TAG` with real tag) ```YAML - repo: https://github.com/crytic/slither rev: $GIT_TAG From d3dadee6e08922fbe68ac742d134be8dcb9cbc19 Mon Sep 17 00:00:00 2001 From: Daniel Bast <2790401+dbast@users.noreply.github.com> Date: Sat, 17 Aug 2024 22:54:48 +0200 Subject: [PATCH 28/40] Fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a85d853699..660f4f8e84 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ docker run -it -v /home/share:/share trailofbits/eth-security-toolbox - repo: https://github.com/crytic/slither rev: $GIT_TAG hooks: - - slither + - id: slither ``` * To generate a Markdown report, use `slither [target] --checklist`. * To generate a Markdown with GitHub source code highlighting, use `slither [target] --checklist --markdown-root https://github.com/ORG/REPO/blob/COMMIT/` (replace `ORG`, `REPO`, `COMMIT`) From 1dca3480f3eed924bec9ba79148c1977ad0bd5ac Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Tue, 20 Aug 2024 21:17:23 -0500 Subject: [PATCH 29/40] require web3 with <5 eth_typing deps --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a669b82a30..4a7e44dca6 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ "pycryptodome>=3.4.6", "crytic-compile>=0.3.7,<0.4.0", # "crytic-compile@git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile", - "web3>=6.0.0", + "web3>=6.20.2", "eth-abi>=4.0.0", "eth-typing>=3.0.0", "eth-utils>=2.1.0", From 63fa86b59f479cd2c180bc97ceb3ae88663dff7c Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 23 Aug 2024 07:30:19 -0500 Subject: [PATCH 30/40] add upper bound --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 344153bbd6..e5739804c8 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ "pycryptodome>=3.4.6", "crytic-compile>=0.3.7,<0.4.0", # "crytic-compile@git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile", - "web3>=6.20.2", + "web3>=6.20.2, <7", "eth-abi>=4.0.0", "eth-typing>=3.0.0", "eth-utils>=2.1.0", From d29f41d725da2aa55844f61c67e43e5834e1cf47 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 23 Aug 2024 07:49:17 -0500 Subject: [PATCH 31/40] disable unused import (#2540) * disable unused import * fmt --- slither/detectors/all_detectors.py | 3 +- tests/e2e/detectors/test_detectors.py | 370 +++++++++++++------------- 2 files changed, 187 insertions(+), 186 deletions(-) diff --git a/slither/detectors/all_detectors.py b/slither/detectors/all_detectors.py index 7c54844316..44a168c2b6 100644 --- a/slither/detectors/all_detectors.py +++ b/slither/detectors/all_detectors.py @@ -97,4 +97,5 @@ from .statements.tautological_compare import TautologicalCompare from .statements.return_bomb import ReturnBomb from .functions.out_of_order_retryable import OutOfOrderRetryable -from .statements.unused_import import UnusedImport + +# from .statements.unused_import import UnusedImport diff --git a/tests/e2e/detectors/test_detectors.py b/tests/e2e/detectors/test_detectors.py index 299f2ea031..2c6a5f55a3 100644 --- a/tests/e2e/detectors/test_detectors.py +++ b/tests/e2e/detectors/test_detectors.py @@ -1714,191 +1714,191 @@ def id_test(test_item: Test): "out_of_order_retryable.sol", "0.8.20", ), - Test( - all_detectors.UnusedImport, - "ConstantContractLevelUsedInContractTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "ConstantContractLevelUsedTopLevelTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "ConstantTopLevelUsedInContractTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "ConstantTopLevelUsedTopLevelTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "ContractUsedInContractTest1.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "ContractUsedInContractTest2.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "ContractUsedTopLevelTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomErrorTopLevelUsedInContractTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomEventContractLevelUsedInContractTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomEventContractLevelUsedTopLevelTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomTypeContractLevelUsedInContractTest1.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomTypeContractLevelUsedInContractTest2.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomTypeContractLevelUsedInContractTest3.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomTypeContractLevelUsedInContractTest4.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomTypeContractLevelUsedTopLevelTest1.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomTypeContractLevelUsedTopLevelTest2.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomTypeTopLevelUsedInContractTest1.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomTypeTopLevelUsedInContractTest2.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomTypeTopLevelUsedInContractTest3.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomTypeTopLevelUsedInContractTest4.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomTypeTopLevelUsedTopLevelTest1.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "CustomTypeTopLevelUsedTopLevelTest2.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "EnumContractLevelUsedInContractTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "EnumContractLevelUsedTopLevelTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "EnumTopLevelUsedInContractTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "EnumTopLevelUsedTopLevelTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "FunctionContractLevelUsedInContractTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "FunctionContractLevelUsedTopLevelTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "FunctionTopLevelUsedInContractTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "FunctionTopLevelUsedTopLevelTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "LibraryUsedInContractTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "LibraryUsedTopLevelTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "StructContractLevelUsedInContractTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "StructContractLevelUsedTopLevelTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "StructTopLevelUsedInContractTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "StructTopLevelUsedTopLevelTest.sol", - "0.8.16", - ), - Test( - all_detectors.UnusedImport, - "C.sol", - "0.8.16", - ), + # Test( + # all_detectors.UnusedImport, + # "ConstantContractLevelUsedInContractTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "ConstantContractLevelUsedTopLevelTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "ConstantTopLevelUsedInContractTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "ConstantTopLevelUsedTopLevelTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "ContractUsedInContractTest1.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "ContractUsedInContractTest2.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "ContractUsedTopLevelTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomErrorTopLevelUsedInContractTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomEventContractLevelUsedInContractTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomEventContractLevelUsedTopLevelTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomTypeContractLevelUsedInContractTest1.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomTypeContractLevelUsedInContractTest2.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomTypeContractLevelUsedInContractTest3.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomTypeContractLevelUsedInContractTest4.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomTypeContractLevelUsedTopLevelTest1.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomTypeContractLevelUsedTopLevelTest2.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomTypeTopLevelUsedInContractTest1.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomTypeTopLevelUsedInContractTest2.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomTypeTopLevelUsedInContractTest3.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomTypeTopLevelUsedInContractTest4.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomTypeTopLevelUsedTopLevelTest1.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "CustomTypeTopLevelUsedTopLevelTest2.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "EnumContractLevelUsedInContractTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "EnumContractLevelUsedTopLevelTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "EnumTopLevelUsedInContractTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "EnumTopLevelUsedTopLevelTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "FunctionContractLevelUsedInContractTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "FunctionContractLevelUsedTopLevelTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "FunctionTopLevelUsedInContractTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "FunctionTopLevelUsedTopLevelTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "LibraryUsedInContractTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "LibraryUsedTopLevelTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "StructContractLevelUsedInContractTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "StructContractLevelUsedTopLevelTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "StructTopLevelUsedInContractTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "StructTopLevelUsedTopLevelTest.sol", + # "0.8.16", + # ), + # Test( + # all_detectors.UnusedImport, + # "C.sol", + # "0.8.16", + # ), ] GENERIC_PATH = "/GENERIC_PATH" From e4657f5f6c6adf1856fdb4921205549044667ade Mon Sep 17 00:00:00 2001 From: Qiuhao Li Date: Fri, 23 Aug 2024 20:52:02 +0800 Subject: [PATCH 32/40] tool: add detector for multiple new reinitializers (#2536) * tool: support reinitializer in slither-check-upgradeability * MissingCalls: don't account reinitializers * tool: add detector for multiple new reinitializers * fix: comments and pylint --- scripts/ci_test_upgradability.sh | 31 ++++- .../tools/upgradeability/checks/all_checks.py | 1 + .../upgradeability/checks/initialization.py | 122 +++++++++++++++++- .../contract_initialization.sol | 54 ++++++++ tests/tools/check_upgradeability/test_10.txt | 6 +- tests/tools/check_upgradeability/test_11.txt | 2 +- tests/tools/check_upgradeability/test_12.txt | 2 +- tests/tools/check_upgradeability/test_13.txt | 8 +- tests/tools/check_upgradeability/test_14.txt | 4 + tests/tools/check_upgradeability/test_15.txt | 15 +++ tests/tools/check_upgradeability/test_2.txt | 2 +- tests/tools/check_upgradeability/test_3.txt | 18 +-- tests/tools/check_upgradeability/test_4.txt | 16 +-- tests/tools/check_upgradeability/test_5.txt | 2 +- tests/tools/check_upgradeability/test_6.txt | 4 +- tests/tools/check_upgradeability/test_7.txt | 4 +- tests/tools/check_upgradeability/test_8.txt | 2 +- tests/tools/check_upgradeability/test_9.txt | 4 +- 18 files changed, 255 insertions(+), 42 deletions(-) create mode 100644 tests/tools/check_upgradeability/test_14.txt create mode 100644 tests/tools/check_upgradeability/test_15.txt diff --git a/scripts/ci_test_upgradability.sh b/scripts/ci_test_upgradability.sh index 0a0d77f519..a4da93873c 100755 --- a/scripts/ci_test_upgradability.sh +++ b/scripts/ci_test_upgradability.sh @@ -2,7 +2,8 @@ ### Test slither-check-upgradeability -DIR_TESTS="tests/check-upgradeability" +DIR_TESTS="tests/tools/check_upgradeability" +solc-select install "0.5.0" solc-select use "0.5.0" slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy > test_1.txt 2>&1 @@ -181,6 +182,32 @@ then exit 255 fi +slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_no_bug_reinitializer --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy > test_14.txt 2>&1 +DIFF=$(diff test_14.txt "$DIR_TESTS/test_14.txt") +if [ "$DIFF" != "" ] +then + echo "slither-check-upgradeability 14 failed" + cat test_14.txt + echo "" + cat "$DIR_TESTS/test_14.txt" + echo "" + echo "$DIFF" + exit 255 +fi + +slither-check-upgradeability "$DIR_TESTS/contract_initialization.sol" Contract_reinitializer_V2 --new-contract-name Counter_reinitializer_V3_V4 > test_15.txt 2>&1 +DIFF=$(diff test_15.txt "$DIR_TESTS/test_15.txt") +if [ "$DIFF" != "" ] +then + echo "slither-check-upgradeability 14 failed" + cat test_15.txt + echo "" + cat "$DIR_TESTS/test_15.txt" + echo "" + echo "$DIFF" + exit 255 +fi + rm test_1.txt rm test_2.txt rm test_3.txt @@ -194,3 +221,5 @@ rm test_10.txt rm test_11.txt rm test_12.txt rm test_13.txt +rm test_14.txt +rm test_15.txt diff --git a/slither/tools/upgradeability/checks/all_checks.py b/slither/tools/upgradeability/checks/all_checks.py index 2289c38085..1581ab5308 100644 --- a/slither/tools/upgradeability/checks/all_checks.py +++ b/slither/tools/upgradeability/checks/all_checks.py @@ -7,6 +7,7 @@ MissingCalls, MultipleCalls, InitializeTarget, + MultipleReinitializers, ) from slither.tools.upgradeability.checks.functions_ids import IDCollision, FunctionShadowing diff --git a/slither/tools/upgradeability/checks/initialization.py b/slither/tools/upgradeability/checks/initialization.py index 2055a322a7..e31a71947b 100644 --- a/slither/tools/upgradeability/checks/initialization.py +++ b/slither/tools/upgradeability/checks/initialization.py @@ -7,6 +7,7 @@ CheckClassification, ) from slither.utils.colors import red +from slither.exceptions import SlitherError logger = logging.getLogger("Slither-check-upgradeability") @@ -18,7 +19,7 @@ class MultipleInitTarget(Exception): def _has_initialize_modifier(function: Function): if not function.modifiers: return False - return any((m.name == "initializer") for m in function.modifiers) + return any((m.name in ("initializer", "reinitializer")) for m in function.modifiers) def _get_initialize_functions(contract): @@ -164,7 +165,7 @@ class MissingInitializerModifier(AbstractCheck): # region wiki_description WIKI_DESCRIPTION = """ -Detect if `Initializable.initializer()` is called. +Detect if `Initializable.initializer()` or `Initializable.reinitializer(uint64)` is called. """ # endregion wiki_description @@ -184,7 +185,7 @@ class MissingInitializerModifier(AbstractCheck): # region wiki_recommendation WIKI_RECOMMENDATION = """ -Use `Initializable.initializer()`. +Use `Initializable.initializer()` or `Initializable.reinitializer(uint64)`. """ # endregion wiki_recommendation @@ -199,15 +200,18 @@ def _check(self): if initializable not in self.contract.inheritance: return [] initializer = self.contract.get_modifier_from_canonical_name("Initializable.initializer()") + reinitializer = self.contract.get_modifier_from_canonical_name( + "Initializable.reinitializer(uint64)" + ) # InitializableInitializer - if initializer is None: + if initializer is None and reinitializer is None: return [] results = [] all_init_functions = _get_initialize_functions(self.contract) for f in all_init_functions: - if initializer not in f.modifiers: - info = [f, " does not call the initializer modifier.\n"] + if initializer not in f.modifiers and reinitializer not in f.modifiers: + info = [f, " does not call the initializer or reinitializer modifier.\n"] json = self.generate_result(info) results.append(json) return results @@ -271,6 +275,9 @@ def _check(self): all_init_functions_called = _get_all_internal_calls(most_derived_init) + [most_derived_init] missing_calls = [f for f in all_init_functions if not f in all_init_functions_called] for f in missing_calls: + # we don't account reinitializers + if any((m.name == "reinitializer") for m in f.modifiers): + continue info = ["Missing call to ", f, " in ", most_derived_init, ".\n"] json = self.generate_result(info) results.append(json) @@ -396,3 +403,106 @@ def _check(self): ] json = self.generate_result(info) return [json] + + +class MultipleReinitializers(AbstractCheck): + ARGUMENT = "multiple-new-reinitializers" + IMPACT = CheckClassification.LOW + + HELP = "Multiple new reinitializers in the updated contract" + WIKI = ( + "https://github.com/crytic/slither/wiki/Upgradeability-Checks#multiple-new-reinitializers" + ) + WIKI_TITLE = "Multiple new reinitializers in the updated contract" + + # region wiki_description + WIKI_DESCRIPTION = """ +Detect multiple new reinitializers in the updated contract`. +""" + # endregion wiki_description + + # region wiki_exploit_scenario + WIKI_EXPLOIT_SCENARIO = """ +```solidity +contract Counter is Initializable { + uint256 public x; + + function initialize(uint256 _x) public initializer { + x = _x; + } + + function changeX() public { + x++; + } +} + +contract CounterV2 is Initializable { + uint256 public x; + uint256 public y; + uint256 public z; + + function initializeV2(uint256 _y) public reinitializer(2) { + y = _y; + } + + function initializeV3(uint256 _z) public reinitializer(3) { + z = _z; + } + + function changeX() public { + x = x + y + z; + } +} +``` +`CounterV2` has two reinitializers with new versions `2` and `3`. If `initializeV3()` is called first, the `initializeV2()` can't be called to initialize `y`, which may brings security risks. +""" + # endregion wiki_exploit_scenario + + # region wiki_recommendation + WIKI_RECOMMENDATION = """ +Do not use multiple reinitializers with higher versions in the updated contract. Please consider combining new reinitializers into a single one. +""" + # endregion wiki_recommendation + + REQUIRE_CONTRACT = True + REQUIRE_CONTRACT_V2 = True + + def _check(self): + contract_v1 = self.contract + contract_v2 = self.contract_v2 + + if contract_v2 is None: + raise SlitherError("multiple-new-reinitializers requires a V2 contract") + + initializerV1 = contract_v1.get_modifier_from_canonical_name("Initializable.initializer()") + reinitializerV1 = contract_v1.get_modifier_from_canonical_name( + "Initializable.reinitializer(uint64)" + ) + reinitializerV2 = contract_v2.get_modifier_from_canonical_name( + "Initializable.reinitializer(uint64)" + ) + + # contractV1 has initializer or reinitializer + if initializerV1 is None and reinitializerV1 is None: + return [] + # contractV2 has reinitializer + if reinitializerV2 is None: + return [] + + initializer_funcs_v1 = _get_initialize_functions(contract_v1) + initializer_funcs_v2 = _get_initialize_functions(contract_v2) + new_reinitializer_funcs = [] + for fv2 in initializer_funcs_v2: + if not any((fv2.full_name == fv1.full_name) for fv1 in initializer_funcs_v1): + new_reinitializer_funcs.append(fv2) + + results = [] + if len(new_reinitializer_funcs) > 1: + for f in new_reinitializer_funcs: + info = [ + f, + " multiple new reinitializers which should be combined into one per upgrade.\n", + ] + json = self.generate_result(info) + results.append(json) + return results diff --git a/tests/tools/check_upgradeability/contract_initialization.sol b/tests/tools/check_upgradeability/contract_initialization.sol index d17125ee96..ab6ab8e515 100644 --- a/tests/tools/check_upgradeability/contract_initialization.sol +++ b/tests/tools/check_upgradeability/contract_initialization.sol @@ -6,6 +6,10 @@ contract Initializable{ _; } + modifier reinitializer(uint64 version){ + _; + } + } contract Contract_no_bug is Initializable{ @@ -16,6 +20,14 @@ contract Contract_no_bug is Initializable{ } +contract Contract_no_bug_reinitializer is Initializable{ + + function initialize() public reinitializer(2){ + + } + +} + contract Contract_lack_to_call_modifier is Initializable{ function initialize() public { @@ -47,3 +59,45 @@ contract Contract_double_call is Contract_no_bug, Contract_no_bug_inherits{ } } + +contract Contract_reinitializer_V2 is Initializable { + uint256 public x; + + function initialize(uint256 _x) public initializer { + x = _x; + } + + function initializeV2(uint256 _x) public reinitializer(2) { + x = _x; + } + + function changeX() public { + x++; + } +} + +contract Counter_reinitializer_V3_V4 is Initializable { + uint256 public x; + uint256 public y; + uint256 public z; + + function initialize(uint256 _x) public initializer { + x = _x; + } + + function initializeV2(uint256 _x) public reinitializer(2) { + x = _x; + } + + function initializeV3(uint256 _y) public reinitializer(3) { + y = _y; + } + + function initializeV4(uint256 _z) public reinitializer(4) { + z = _z; + } + + function changeX() public { + x = x + y + z; + } +} \ No newline at end of file diff --git a/tests/tools/check_upgradeability/test_10.txt b/tests/tools/check_upgradeability/test_10.txt index 3d317aca5b..9a7e022c1e 100644 --- a/tests/tools/check_upgradeability/test_10.txt +++ b/tests/tools/check_upgradeability/test_10.txt @@ -2,12 +2,12 @@ INFO:Slither: Initializable contract not found, the contract does not follow a standard initalization schema. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initializable-is-missing INFO:Slither: -ContractV1.destination (tests/check-upgradeability/contractV1.sol#2) was not constant but ContractV2.destination (tests/check-upgradeability/contract_v2_constant.sol#2) is. +ContractV1.destination (tests/tools/check_upgradeability/contractV1.sol#2) was not constant but ContractV2.destination (tests/tools/check_upgradeability/contract_v2_constant.sol#2) is. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#variables-that-should-not-be-constant INFO:Slither: -Variable missing in ContractV2 (tests/check-upgradeability/contract_v2_constant.sol#1-3): ContractV1.destination (tests/check-upgradeability/contractV1.sol#2) +Variable missing in ContractV2 (tests/tools/check_upgradeability/contract_v2_constant.sol#1-3): ContractV1.destination (tests/tools/check_upgradeability/contractV1.sol#2) Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#missing-variables INFO:Slither: Initializable contract not found, the contract does not follow a standard initalization schema. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initializable-is-missing -INFO:Slither:4 findings, 21 detectors run +INFO:Slither:4 findings, 22 detectors run diff --git a/tests/tools/check_upgradeability/test_11.txt b/tests/tools/check_upgradeability/test_11.txt index e2ad677b12..d942ce6b7c 100644 --- a/tests/tools/check_upgradeability/test_11.txt +++ b/tests/tools/check_upgradeability/test_11.txt @@ -2,6 +2,6 @@ INFO:Slither: Initializable contract not found, the contract does not follow a standard initalization schema. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initializable-is-missing INFO:Slither: -ContractV1.destination (tests/check-upgradeability/contract_v1_var_init.sol#2) is a state variable with an initial value. +ContractV1.destination (tests/tools/check_upgradeability/contract_v1_var_init.sol#2) is a state variable with an initial value. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#state-variable-initialized INFO:Slither:2 findings, 8 detectors run diff --git a/tests/tools/check_upgradeability/test_12.txt b/tests/tools/check_upgradeability/test_12.txt index 353d8ebdb7..7641e8335b 100644 --- a/tests/tools/check_upgradeability/test_12.txt +++ b/tests/tools/check_upgradeability/test_12.txt @@ -4,4 +4,4 @@ Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initiali INFO:Slither: Initializable contract not found, the contract does not follow a standard initalization schema. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initializable-is-missing -INFO:Slither:2 findings, 21 detectors run +INFO:Slither:2 findings, 22 detectors run diff --git a/tests/tools/check_upgradeability/test_13.txt b/tests/tools/check_upgradeability/test_13.txt index 9635f9a43b..e39b9b1ac3 100644 --- a/tests/tools/check_upgradeability/test_13.txt +++ b/tests/tools/check_upgradeability/test_13.txt @@ -2,11 +2,11 @@ INFO:Slither: Initializable contract not found, the contract does not follow a standard initalization schema. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initializable-is-missing INFO:Slither: -Different variables between ContractV1 (tests/check-upgradeability/contractV1_struct.sol#1-8) and ContractV2 (tests/check-upgradeability/contractV2_struct_bug.sol#1-8) - ContractV1.foo (tests/check-upgradeability/contractV1_struct.sol#7) - ContractV2.foo (tests/check-upgradeability/contractV2_struct_bug.sol#7) +Different variables between ContractV1 (tests/tools/check_upgradeability/contractV1_struct.sol#1-8) and ContractV2 (tests/tools/check_upgradeability/contractV2_struct_bug.sol#1-8) + ContractV1.foo (tests/tools/check_upgradeability/contractV1_struct.sol#7) + ContractV2.foo (tests/tools/check_upgradeability/contractV2_struct_bug.sol#7) Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#incorrect-variables-with-the-v2 INFO:Slither: Initializable contract not found, the contract does not follow a standard initalization schema. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initializable-is-missing -INFO:Slither:3 findings, 21 detectors run +INFO:Slither:3 findings, 22 detectors run diff --git a/tests/tools/check_upgradeability/test_14.txt b/tests/tools/check_upgradeability/test_14.txt new file mode 100644 index 0000000000..da412418ec --- /dev/null +++ b/tests/tools/check_upgradeability/test_14.txt @@ -0,0 +1,4 @@ +INFO:Slither: +Contract_no_bug_reinitializer (tests/tools/check_upgradeability/contract_initialization.sol#23-29) needs to be initialized by Contract_no_bug_reinitializer.initialize() (tests/tools/check_upgradeability/contract_initialization.sol#25-27). +Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initialize-function +INFO:Slither:1 findings, 12 detectors run diff --git a/tests/tools/check_upgradeability/test_15.txt b/tests/tools/check_upgradeability/test_15.txt new file mode 100644 index 0000000000..d9c588f737 --- /dev/null +++ b/tests/tools/check_upgradeability/test_15.txt @@ -0,0 +1,15 @@ +INFO:Slither: +Contract_reinitializer_V2 (tests/tools/check_upgradeability/contract_initialization.sol#63-77) needs to be initialized by Contract_reinitializer_V2.initialize(uint256) (tests/tools/check_upgradeability/contract_initialization.sol#66-68). +Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initialize-function +INFO:Slither: +Extra variables in Counter_reinitializer_V3_V4 (tests/tools/check_upgradeability/contract_initialization.sol#79-104): Counter_reinitializer_V3_V4.y (tests/tools/check_upgradeability/contract_initialization.sol#81) +Extra variables in Counter_reinitializer_V3_V4 (tests/tools/check_upgradeability/contract_initialization.sol#79-104): Counter_reinitializer_V3_V4.z (tests/tools/check_upgradeability/contract_initialization.sol#82) +Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#extra-variables-in-the-v2 +INFO:Slither: +Counter_reinitializer_V3_V4.initializeV3(uint256) (tests/tools/check_upgradeability/contract_initialization.sol#92-94) multiple new reinitializers which should be combined into one per upgrade. +Counter_reinitializer_V3_V4.initializeV4(uint256) (tests/tools/check_upgradeability/contract_initialization.sol#96-98) multiple new reinitializers which should be combined into one per upgrade. +Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#multiple-new-reinitializers +INFO:Slither: +Counter_reinitializer_V3_V4 (tests/tools/check_upgradeability/contract_initialization.sol#79-104) needs to be initialized by Counter_reinitializer_V3_V4.initialize(uint256) (tests/tools/check_upgradeability/contract_initialization.sol#84-86). +Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initialize-function +INFO:Slither:6 findings, 22 detectors run diff --git a/tests/tools/check_upgradeability/test_2.txt b/tests/tools/check_upgradeability/test_2.txt index dcf910c00d..a3970ffc12 100644 --- a/tests/tools/check_upgradeability/test_2.txt +++ b/tests/tools/check_upgradeability/test_2.txt @@ -4,4 +4,4 @@ Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initiali INFO:Slither: Initializable contract not found, the contract does not follow a standard initalization schema. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initializable-is-missing -INFO:Slither:2 findings, 25 detectors run +INFO:Slither:2 findings, 26 detectors run diff --git a/tests/tools/check_upgradeability/test_3.txt b/tests/tools/check_upgradeability/test_3.txt index fb694d5fb0..5cdc9fc7e2 100644 --- a/tests/tools/check_upgradeability/test_3.txt +++ b/tests/tools/check_upgradeability/test_3.txt @@ -2,22 +2,22 @@ INFO:Slither: Initializable contract not found, the contract does not follow a standard initalization schema. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initializable-is-missing INFO:Slither: -Different variables between ContractV2 (tests/check-upgradeability/contractV2_bug.sol#1-5) and Proxy (tests/check-upgradeability/proxy.sol#7-27) - ContractV2.destination (tests/check-upgradeability/contractV2_bug.sol#2) - Proxy.destination (tests/check-upgradeability/proxy.sol#9) +Different variables between ContractV2 (tests/tools/check_upgradeability/contractV2_bug.sol#1-5) and Proxy (tests/tools/check_upgradeability/proxy.sol#7-27) + ContractV2.destination (tests/tools/check_upgradeability/contractV2_bug.sol#2) + Proxy.destination (tests/tools/check_upgradeability/proxy.sol#9) Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#incorrect-variables-with-the-proxy INFO:Slither: -Function shadowing found: ContractV2.myFunc (tests/check-upgradeability/contractV2_bug.sol#4) Proxy.myFunc() (tests/check-upgradeability/proxy.sol#11) +Function shadowing found: ContractV2.myFunc (tests/tools/check_upgradeability/contractV2_bug.sol#4) Proxy.myFunc() (tests/tools/check_upgradeability/proxy.sol#11) Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#functions-shadowing INFO:Slither: -Different variables between ContractV1 (tests/check-upgradeability/contractV1.sol#1-3) and ContractV2 (tests/check-upgradeability/contractV2_bug.sol#1-5) - ContractV1.destination (tests/check-upgradeability/contractV1.sol#2) - ContractV2.destination (tests/check-upgradeability/contractV2_bug.sol#2) +Different variables between ContractV1 (tests/tools/check_upgradeability/contractV1.sol#1-3) and ContractV2 (tests/tools/check_upgradeability/contractV2_bug.sol#1-5) + ContractV1.destination (tests/tools/check_upgradeability/contractV1.sol#2) + ContractV2.destination (tests/tools/check_upgradeability/contractV2_bug.sol#2) Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#incorrect-variables-with-the-v2 INFO:Slither: -Extra variables in ContractV2 (tests/check-upgradeability/contractV2_bug.sol#1-5): ContractV2.myFunc (tests/check-upgradeability/contractV2_bug.sol#4) +Extra variables in ContractV2 (tests/tools/check_upgradeability/contractV2_bug.sol#1-5): ContractV2.myFunc (tests/tools/check_upgradeability/contractV2_bug.sol#4) Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#extra-variables-in-the-v2 INFO:Slither: Initializable contract not found, the contract does not follow a standard initalization schema. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initializable-is-missing -INFO:Slither:6 findings, 25 detectors run +INFO:Slither:6 findings, 26 detectors run diff --git a/tests/tools/check_upgradeability/test_4.txt b/tests/tools/check_upgradeability/test_4.txt index 4752eb706c..eb088324d2 100644 --- a/tests/tools/check_upgradeability/test_4.txt +++ b/tests/tools/check_upgradeability/test_4.txt @@ -2,19 +2,19 @@ INFO:Slither: Initializable contract not found, the contract does not follow a standard initalization schema. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initializable-is-missing INFO:Slither: -Different variables between ContractV2 (tests/check-upgradeability/contractV2_bug2.sol#4-6) and Proxy (tests/check-upgradeability/proxy.sol#7-27) - Base.val (tests/check-upgradeability/contractV2_bug2.sol#2) - Proxy.destination (tests/check-upgradeability/proxy.sol#9) +Different variables between ContractV2 (tests/tools/check_upgradeability/contractV2_bug2.sol#4-6) and Proxy (tests/tools/check_upgradeability/proxy.sol#7-27) + Base.val (tests/tools/check_upgradeability/contractV2_bug2.sol#2) + Proxy.destination (tests/tools/check_upgradeability/proxy.sol#9) Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#incorrect-variables-with-the-proxy INFO:Slither: -Different variables between ContractV1 (tests/check-upgradeability/contractV1.sol#1-3) and ContractV2 (tests/check-upgradeability/contractV2_bug2.sol#4-6) - ContractV1.destination (tests/check-upgradeability/contractV1.sol#2) - Base.val (tests/check-upgradeability/contractV2_bug2.sol#2) +Different variables between ContractV1 (tests/tools/check_upgradeability/contractV1.sol#1-3) and ContractV2 (tests/tools/check_upgradeability/contractV2_bug2.sol#4-6) + ContractV1.destination (tests/tools/check_upgradeability/contractV1.sol#2) + Base.val (tests/tools/check_upgradeability/contractV2_bug2.sol#2) Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#incorrect-variables-with-the-v2 INFO:Slither: -Extra variables in ContractV2 (tests/check-upgradeability/contractV2_bug2.sol#4-6): ContractV2.destination (tests/check-upgradeability/contractV2_bug2.sol#5) +Extra variables in ContractV2 (tests/tools/check_upgradeability/contractV2_bug2.sol#4-6): ContractV2.destination (tests/tools/check_upgradeability/contractV2_bug2.sol#5) Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#extra-variables-in-the-v2 INFO:Slither: Initializable contract not found, the contract does not follow a standard initalization schema. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initializable-is-missing -INFO:Slither:5 findings, 25 detectors run +INFO:Slither:5 findings, 26 detectors run diff --git a/tests/tools/check_upgradeability/test_5.txt b/tests/tools/check_upgradeability/test_5.txt index 805602ee44..da889fb59c 100644 --- a/tests/tools/check_upgradeability/test_5.txt +++ b/tests/tools/check_upgradeability/test_5.txt @@ -1,4 +1,4 @@ INFO:Slither: -Contract_no_bug (tests/check-upgradeability/contract_initialization.sol#11-17) needs to be initialized by Contract_no_bug.initialize() (tests/check-upgradeability/contract_initialization.sol#13-15). +Contract_no_bug (tests/tools/check_upgradeability/contract_initialization.sol#15-21) needs to be initialized by Contract_no_bug.initialize() (tests/tools/check_upgradeability/contract_initialization.sol#17-19). Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initialize-function INFO:Slither:1 findings, 12 detectors run diff --git a/tests/tools/check_upgradeability/test_6.txt b/tests/tools/check_upgradeability/test_6.txt index 663cb62d07..80b8d8b516 100644 --- a/tests/tools/check_upgradeability/test_6.txt +++ b/tests/tools/check_upgradeability/test_6.txt @@ -1,7 +1,7 @@ INFO:Slither: -Contract_lack_to_call_modifier (tests/check-upgradeability/contract_initialization.sol#19-24) needs to be initialized by Contract_lack_to_call_modifier.initialize() (tests/check-upgradeability/contract_initialization.sol#21-23). +Contract_lack_to_call_modifier (tests/tools/check_upgradeability/contract_initialization.sol#31-36) needs to be initialized by Contract_lack_to_call_modifier.initialize() (tests/tools/check_upgradeability/contract_initialization.sol#33-35). Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initialize-function INFO:Slither: -Contract_lack_to_call_modifier.initialize() (tests/check-upgradeability/contract_initialization.sol#21-23) does not call the initializer modifier. +Contract_lack_to_call_modifier.initialize() (tests/tools/check_upgradeability/contract_initialization.sol#33-35) does not call the initializer or reinitializer modifier. Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initializer-is-not-called INFO:Slither:2 findings, 12 detectors run diff --git a/tests/tools/check_upgradeability/test_7.txt b/tests/tools/check_upgradeability/test_7.txt index 9f232338e7..02607207be 100644 --- a/tests/tools/check_upgradeability/test_7.txt +++ b/tests/tools/check_upgradeability/test_7.txt @@ -1,7 +1,7 @@ INFO:Slither: -Contract_not_called_super_init (tests/check-upgradeability/contract_initialization.sol#26-32) needs to be initialized by Contract_not_called_super_init.initialize() (tests/check-upgradeability/contract_initialization.sol#28-30). +Contract_not_called_super_init (tests/tools/check_upgradeability/contract_initialization.sol#38-44) needs to be initialized by Contract_not_called_super_init.initialize() (tests/tools/check_upgradeability/contract_initialization.sol#40-42). Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initialize-function INFO:Slither: -Missing call to Contract_no_bug.initialize() (tests/check-upgradeability/contract_initialization.sol#13-15) in Contract_not_called_super_init.initialize() (tests/check-upgradeability/contract_initialization.sol#28-30). +Missing call to Contract_no_bug.initialize() (tests/tools/check_upgradeability/contract_initialization.sol#17-19) in Contract_not_called_super_init.initialize() (tests/tools/check_upgradeability/contract_initialization.sol#40-42). Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initialize-functions-are-not-called INFO:Slither:2 findings, 12 detectors run diff --git a/tests/tools/check_upgradeability/test_8.txt b/tests/tools/check_upgradeability/test_8.txt index 38c71e28c1..8cd703bea8 100644 --- a/tests/tools/check_upgradeability/test_8.txt +++ b/tests/tools/check_upgradeability/test_8.txt @@ -1,4 +1,4 @@ INFO:Slither: -Contract_no_bug_inherits (tests/check-upgradeability/contract_initialization.sol#34-40) needs to be initialized by Contract_no_bug_inherits.initialize() (tests/check-upgradeability/contract_initialization.sol#36-38). +Contract_no_bug_inherits (tests/tools/check_upgradeability/contract_initialization.sol#46-52) needs to be initialized by Contract_no_bug_inherits.initialize() (tests/tools/check_upgradeability/contract_initialization.sol#48-50). Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initialize-function INFO:Slither:1 findings, 12 detectors run diff --git a/tests/tools/check_upgradeability/test_9.txt b/tests/tools/check_upgradeability/test_9.txt index a67578a08f..cece4f6ea8 100644 --- a/tests/tools/check_upgradeability/test_9.txt +++ b/tests/tools/check_upgradeability/test_9.txt @@ -1,7 +1,7 @@ INFO:Slither: -Contract_double_call (tests/check-upgradeability/contract_initialization.sol#42-49) needs to be initialized by Contract_double_call.initialize() (tests/check-upgradeability/contract_initialization.sol#44-47). +Contract_double_call (tests/tools/check_upgradeability/contract_initialization.sol#54-61) needs to be initialized by Contract_double_call.initialize() (tests/tools/check_upgradeability/contract_initialization.sol#56-59). Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initialize-function INFO:Slither: -Contract_no_bug.initialize() (tests/check-upgradeability/contract_initialization.sol#13-15) is called multiple times in Contract_double_call.initialize() (tests/check-upgradeability/contract_initialization.sol#44-47). +Contract_no_bug.initialize() (tests/tools/check_upgradeability/contract_initialization.sol#17-19) is called multiple times in Contract_double_call.initialize() (tests/tools/check_upgradeability/contract_initialization.sol#56-59). Reference: https://github.com/crytic/slither/wiki/Upgradeability-Checks#initialize-functions-are-called-multiple-times INFO:Slither:2 findings, 12 detectors run From 809d1b515506ff2d7443c0a38cac0f15d4083714 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2024 07:54:09 -0500 Subject: [PATCH 33/40] Bump pypa/gh-action-pip-audit from 1.0.8 to 1.1.0 (#2531) Bumps [pypa/gh-action-pip-audit](https://github.com/pypa/gh-action-pip-audit) from 1.0.8 to 1.1.0. - [Release notes](https://github.com/pypa/gh-action-pip-audit/releases) - [Commits](https://github.com/pypa/gh-action-pip-audit/compare/v1.0.8...v1.1.0) --- updated-dependencies: - dependency-name: pypa/gh-action-pip-audit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/pip-audit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pip-audit.yml b/.github/workflows/pip-audit.yml index 1c0a1d40ad..f4a028c8c6 100644 --- a/.github/workflows/pip-audit.yml +++ b/.github/workflows/pip-audit.yml @@ -34,6 +34,6 @@ jobs: python -m pip install . - name: Run pip-audit - uses: pypa/gh-action-pip-audit@v1.0.8 + uses: pypa/gh-action-pip-audit@v1.1.0 with: virtual-environment: /tmp/pip-audit-env From aeeb2d368802844733671e35200b30b5f5bdcf5c Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 23 Aug 2024 08:20:00 -0500 Subject: [PATCH 34/40] prepare 0.10.4 release --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e5739804c8..ef9d81f203 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ description="Slither is a Solidity and Vyper static analysis framework written in Python 3.", url="https://github.com/crytic/slither", author="Trail of Bits", - version="0.10.3", + version="0.10.4", packages=find_packages(), python_requires=">=3.8", install_requires=[ From 7bfa87ad76e39f7a046b20a7342e1e4c8239ddce Mon Sep 17 00:00:00 2001 From: Simone Date: Mon, 9 Sep 2024 10:38:28 +0200 Subject: [PATCH 35/40] Add support custom errors in require --- .../core/declarations/solidity_variables.py | 1 + .../require-error.sol-0.8.27-compact.zip | Bin 0 -> 3685 bytes .../require-error.sol-0.8.27-compact.json | 5 +++++ .../solc_parsing/test_data/require-error.sol | 20 ++++++++++++++++++ 4 files changed, 26 insertions(+) create mode 100644 tests/e2e/solc_parsing/test_data/compile/require-error.sol-0.8.27-compact.zip create mode 100644 tests/e2e/solc_parsing/test_data/expected/require-error.sol-0.8.27-compact.json create mode 100644 tests/e2e/solc_parsing/test_data/require-error.sol diff --git a/slither/core/declarations/solidity_variables.py b/slither/core/declarations/solidity_variables.py index 8094ab7c35..ce8477ab23 100644 --- a/slither/core/declarations/solidity_variables.py +++ b/slither/core/declarations/solidity_variables.py @@ -50,6 +50,7 @@ "assert(bool)": [], "require(bool)": [], "require(bool,string)": [], + "require(bool,error)": [], # Solidity 0.8.26 via-ir and Solidity >= 0.8.27 "revert()": [], "revert(string)": [], "revert ": [], diff --git a/tests/e2e/solc_parsing/test_data/compile/require-error.sol-0.8.27-compact.zip b/tests/e2e/solc_parsing/test_data/compile/require-error.sol-0.8.27-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..63aa223b37ffa0e9d4e552aa106161a54fd79272 GIT binary patch literal 3685 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 literal 0 HcmV?d00001 diff --git a/tests/e2e/solc_parsing/test_data/expected/require-error.sol-0.8.27-compact.json b/tests/e2e/solc_parsing/test_data/expected/require-error.sol-0.8.27-compact.json new file mode 100644 index 0000000000..3c3089c048 --- /dev/null +++ b/tests/e2e/solc_parsing/test_data/expected/require-error.sol-0.8.27-compact.json @@ -0,0 +1,5 @@ +{ + "TestToken": { + "transferWithRequireError(address,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n2->3;\n3[label=\"Node Type: EXPRESSION 3\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/e2e/solc_parsing/test_data/require-error.sol b/tests/e2e/solc_parsing/test_data/require-error.sol new file mode 100644 index 0000000000..97c8ecac4f --- /dev/null +++ b/tests/e2e/solc_parsing/test_data/require-error.sol @@ -0,0 +1,20 @@ +pragma solidity 0.8.27; + +/// Insufficient balance for transfer. Needed `required` but only +/// `available` available. +/// @param available balance available. +/// @param required requested amount to transfer. +error InsufficientBalance(uint256 available, uint256 required); + +contract TestToken { + mapping(address => uint) balance; + function transferWithRequireError(address to, uint256 amount) public { + require( + balance[msg.sender] >= amount, + InsufficientBalance(balance[msg.sender], amount) + ); + balance[msg.sender] -= amount; + balance[to] += amount; + } + // ... +} From 5d55bc5752070f28330acafe890100b48b59aff0 Mon Sep 17 00:00:00 2001 From: Simone Date: Mon, 9 Sep 2024 10:44:29 +0200 Subject: [PATCH 36/40] Add test --- tests/e2e/solc_parsing/test_ast_parsing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/solc_parsing/test_ast_parsing.py b/tests/e2e/solc_parsing/test_ast_parsing.py index ca3872f8c5..6ec7b6fbd2 100644 --- a/tests/e2e/solc_parsing/test_ast_parsing.py +++ b/tests/e2e/solc_parsing/test_ast_parsing.py @@ -475,6 +475,7 @@ def make_version(minor: int, patch_min: int, patch_max: int) -> List[str]: Test("solidity-0.8.24.sol", ["0.8.24"], solc_args="--evm-version cancun"), Test("scope/inherited_function_scope.sol", ["0.8.24"]), Test("using_for_global_user_defined_operator_1.sol", ["0.8.24"]), + Test("require-error.sol", ["0.8.27"]), ] # create the output folder if needed try: From 109c31adcf0b31f4a45c1ce63ab97db63496844e Mon Sep 17 00:00:00 2001 From: Simone Date: Wed, 11 Sep 2024 14:01:59 +0200 Subject: [PATCH 37/40] Add require with error --- slither/core/cfg/node.py | 3 ++- slither/printers/summary/require_calls.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/slither/core/cfg/node.py b/slither/core/cfg/node.py index 87d0e16a2e..f600d0f43d 100644 --- a/slither/core/cfg/node.py +++ b/slither/core/cfg/node.py @@ -529,7 +529,8 @@ def contains_require_or_assert(self) -> bool: bool: True if the node has a require or assert call """ return any( - c.name in ["require(bool)", "require(bool,string)", "assert(bool)"] + c.name + in ["require(bool)", "require(bool,string)", "require(bool,error)", "assert(bool)"] for c in self.internal_calls ) diff --git a/slither/printers/summary/require_calls.py b/slither/printers/summary/require_calls.py index 7823de1600..ae79e9ed66 100644 --- a/slither/printers/summary/require_calls.py +++ b/slither/printers/summary/require_calls.py @@ -11,6 +11,7 @@ SolidityFunction("assert(bool)"), SolidityFunction("require(bool)"), SolidityFunction("require(bool,string)"), + SolidityFunction("require(bool,error)"), ] From 2c792b2b73c6c1fbbf5464bd1f9fc8ccedf0c0bf Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Wed, 11 Sep 2024 10:25:38 -0500 Subject: [PATCH 38/40] fix: breaking change in upload artifact that ignores hidden files --- .github/actions/upload-coverage/action.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/actions/upload-coverage/action.yml b/.github/actions/upload-coverage/action.yml index 02fb82f65c..541b93111d 100644 --- a/.github/actions/upload-coverage/action.yml +++ b/.github/actions/upload-coverage/action.yml @@ -27,4 +27,5 @@ runs: path: | .coverage.* *.lcov - if-no-files-found: ignore \ No newline at end of file + if-no-files-found: ignore + include-hidden-files: true From 584d64c73fff7e3d7f08d952725ed4645bcc8897 Mon Sep 17 00:00:00 2001 From: Hamdi Allam Date: Wed, 25 Sep 2024 14:43:01 -0700 Subject: [PATCH 39/40] add event as value member --- slither/slithir/operations/member.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/slither/slithir/operations/member.py b/slither/slithir/operations/member.py index 0942813cfc..193f6f177e 100644 --- a/slither/slithir/operations/member.py +++ b/slither/slithir/operations/member.py @@ -1,5 +1,5 @@ from typing import List, Union -from slither.core.declarations import Contract, Function +from slither.core.declarations import Contract, Function, Event from slither.core.declarations.custom_error import CustomError from slither.core.declarations.enum import Enum from slither.core.declarations.solidity_import_placeholder import SolidityImportPlaceHolder @@ -33,14 +33,14 @@ def __init__( # Can be an ElementaryType because of bytes.concat, string.concat assert is_valid_rvalue(variable_left) or isinstance( variable_left, - (Contract, Enum, Function, CustomError, SolidityImportPlaceHolder, ElementaryType), + (Contract, Enum, Function, Event, CustomError, SolidityImportPlaceHolder, ElementaryType), ) assert isinstance(variable_right, Constant) assert isinstance(result, ReferenceVariable) super().__init__() self._variable_left: Union[ - RVALUE, Contract, Enum, Function, CustomError, SolidityImportPlaceHolder, ElementaryType + RVALUE, Contract, Enum, Function, Event, CustomError, SolidityImportPlaceHolder, ElementaryType ] = variable_left self._variable_right = variable_right self._lvalue = result From 2075e6f1e9f7f5ba14364db256b2e6a3517629ec Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Thu, 26 Sep 2024 18:02:35 -0500 Subject: [PATCH 40/40] fmt --- slither/slithir/operations/member.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/slither/slithir/operations/member.py b/slither/slithir/operations/member.py index 193f6f177e..55979572c5 100644 --- a/slither/slithir/operations/member.py +++ b/slither/slithir/operations/member.py @@ -33,14 +33,29 @@ def __init__( # Can be an ElementaryType because of bytes.concat, string.concat assert is_valid_rvalue(variable_left) or isinstance( variable_left, - (Contract, Enum, Function, Event, CustomError, SolidityImportPlaceHolder, ElementaryType), + ( + Contract, + Enum, + Function, + Event, + CustomError, + SolidityImportPlaceHolder, + ElementaryType, + ), ) assert isinstance(variable_right, Constant) assert isinstance(result, ReferenceVariable) super().__init__() self._variable_left: Union[ - RVALUE, Contract, Enum, Function, Event, CustomError, SolidityImportPlaceHolder, ElementaryType + RVALUE, + Contract, + Enum, + Function, + Event, + CustomError, + SolidityImportPlaceHolder, + ElementaryType, ] = variable_left self._variable_right = variable_right self._lvalue = result