Merge pull request #2506 from crytic/dev

sync master <> dev
pull/2542/head
alpharush 3 months ago committed by GitHub
commit 46061c5d27
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      .github/scripts/tool_test_runner.sh
  2. 2
      .github/workflows/docker.yml
  3. 2
      .github/workflows/pip-audit.yml
  4. 4
      .github/workflows/publish.yml
  5. 1
      Dockerfile
  6. 31
      scripts/ci_test_upgradability.sh
  7. 4
      setup.py
  8. 8
      slither/__main__.py
  9. 3
      slither/detectors/all_detectors.py
  10. 2
      slither/detectors/attributes/incorrect_solc.py
  11. 3
      slither/detectors/functions/arbitrary_send_eth.py
  12. 2
      slither/detectors/functions/dead_code.py
  13. 4
      slither/printers/summary/loc.py
  14. 4
      slither/tools/mutator/__main__.py
  15. 39
      slither/tools/mutator/mutators/AOR.py
  16. 4
      slither/tools/mutator/mutators/LIR.py
  17. 8
      slither/tools/mutator/mutators/abstract_mutator.py
  18. 2
      slither/tools/mutator/utils/file_handling.py
  19. 7
      slither/tools/mutator/utils/testing_generated_mutant.py
  20. 1
      slither/tools/upgradeability/checks/all_checks.py
  21. 122
      slither/tools/upgradeability/checks/initialization.py
  22. 4
      slither/utils/command_line.py
  23. 26
      slither/utils/myprettytable.py
  24. 8
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_6_11_arbitrary_send_eth_sol__0.txt
  25. 8
      tests/e2e/detectors/snapshots/detectors__detector_ArbitrarySendEth_0_7_6_arbitrary_send_eth_sol__0.txt
  26. 7
      tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol
  27. BIN
      tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol-0.6.11.zip
  28. 7
      tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol
  29. BIN
      tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol-0.7.6.zip
  30. 370
      tests/e2e/detectors/test_detectors.py
  31. 20
      tests/e2e/test_cli.py
  32. 54
      tests/tools/check_upgradeability/contract_initialization.sol
  33. 6
      tests/tools/check_upgradeability/test_10.txt
  34. 2
      tests/tools/check_upgradeability/test_11.txt
  35. 2
      tests/tools/check_upgradeability/test_12.txt
  36. 8
      tests/tools/check_upgradeability/test_13.txt
  37. 4
      tests/tools/check_upgradeability/test_14.txt
  38. 15
      tests/tools/check_upgradeability/test_15.txt
  39. 2
      tests/tools/check_upgradeability/test_2.txt
  40. 18
      tests/tools/check_upgradeability/test_3.txt
  41. 16
      tests/tools/check_upgradeability/test_4.txt
  42. 2
      tests/tools/check_upgradeability/test_5.txt
  43. 4
      tests/tools/check_upgradeability/test_6.txt
  44. 4
      tests/tools/check_upgradeability/test_7.txt
  45. 2
      tests/tools/check_upgradeability/test_8.txt
  46. 4
      tests/tools/check_upgradeability/test_9.txt
  47. 0
      tests/tools/mutator/__init__.py
  48. 7
      tests/tools/mutator/test_data/test_source_unit/README.md
  49. 7
      tests/tools/mutator/test_data/test_source_unit/foundry.toml
  50. 12
      tests/tools/mutator/test_data/test_source_unit/script/Counter.s.sol
  51. 14
      tests/tools/mutator/test_data/test_source_unit/src/Counter.sol
  52. 24
      tests/tools/mutator/test_data/test_source_unit/test/Counter.t.sol
  53. 133
      tests/tools/mutator/test_mutator.py

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

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

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

@ -44,10 +44,10 @@ 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
uses: sigstore/gh-action-sigstore-python@v3.0.0
with:
inputs: ./dist/*.tar.gz ./dist/*.whl
release-signing-artifacts: true

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

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

@ -13,11 +13,11 @@ setup(
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",
"web3>=6.0.0",
"web3>=6.20.2, <7",
"eth-abi>=4.0.0",
"eth-typing>=3.0.0",
"eth-utils>=2.1.0",

@ -14,7 +14,7 @@ from importlib import metadata
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)
slither_instances = []
results_detectors = []
results_printers = []

@ -97,4 +97,5 @@ from .operations.incorrect_exp import IncorrectOperatorExponentiation
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

@ -71,7 +71,7 @@ Consider using the latest version of Solidity for testing."""
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

@ -30,6 +30,7 @@ from slither.slithir.operations import (
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"),

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

@ -17,8 +17,8 @@ from slither.utils.output import Output
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"

@ -6,7 +6,7 @@ import shutil
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 = [

@ -2,7 +2,12 @@ from typing import Dict
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 @@ class AOR(AbstractMutator): # pylint: disable=too-few-public-methods
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

@ -31,7 +31,7 @@ class LIR(AbstractMutator): # pylint: disable=too-few-public-methods
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 @@ class LIR(AbstractMutator): # pylint: disable=too-few-public-methods
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

@ -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 @@ class AbstractMutator(
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 @@ class AbstractMutator(
(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 @@ class AbstractMutator(
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

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

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

@ -7,6 +7,7 @@ from slither.tools.upgradeability.checks.initialization import (
MissingCalls,
MultipleCalls,
InitializeTarget,
MultipleReinitializers,
)
from slither.tools.upgradeability.checks.functions_ids import IDCollision, FunctionShadowing

@ -7,6 +7,7 @@ from slither.tools.upgradeability.checks.abstract_checks import (
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 @@ contract Contract{
# region wiki_recommendation
WIKI_RECOMMENDATION = """
Use `Initializable.initializer()`.
Use `Initializable.initializer()` or `Initializable.reinitializer(uint64)`.
"""
# endregion wiki_recommendation
@ -199,15 +200,18 @@ Use `Initializable.initializer()`.
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 @@ Ensure all the initialize functions are reached by the most derived initialize f
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 @@ Ensure that the function is called at deployment.
]
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

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

@ -1,3 +1,4 @@
from shutil import get_terminal_size
from typing import List, Dict, Union
from prettytable import PrettyTable
@ -7,7 +8,12 @@ from slither.utils.colors import Colors
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 @@ class MyPrettyTable:
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 @@ class MyPrettyTable:
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

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

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

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

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

@ -1714,191 +1714,191 @@ ALL_TESTS = [
"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"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -0,0 +1,7 @@
# Counter
Init using :
```shell
forge install --no-commit --no-git .
```

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

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

@ -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++;
}
}

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

@ -0,0 +1,133 @@
import argparse
from contextlib import contextmanager
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
from unittest import mock
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"
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):
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, solc_binary_path): # pylint: disable=unused-argument
with change_directory(TEST_DATA_DIR / "test_source_unit"):
main()
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, solc=solc_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()
@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"
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()
@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)
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]
Loading…
Cancel
Save