mirror of https://github.com/crytic/slither
commit
6a10e0a1e1
@ -0,0 +1,88 @@ |
||||
SHELL := /bin/bash
|
||||
|
||||
PY_MODULE := slither
|
||||
TEST_MODULE := tests
|
||||
|
||||
ALL_PY_SRCS := $(shell find $(PY_MODULE) -name '*.py') \
|
||||
$(shell find test -name '*.py')
|
||||
|
||||
# Optionally overriden by the user, if they're using a virtual environment manager.
|
||||
VENV ?= env
|
||||
|
||||
# On Windows, venv scripts/shims are under `Scripts` instead of `bin`.
|
||||
VENV_BIN := $(VENV)/bin
|
||||
ifeq ($(OS),Windows_NT) |
||||
VENV_BIN := $(VENV)/Scripts
|
||||
endif |
||||
|
||||
# Optionally overridden by the user in the `release` target.
|
||||
BUMP_ARGS :=
|
||||
|
||||
# Optionally overridden by the user in the `test` target.
|
||||
TESTS :=
|
||||
|
||||
# Optionally overridden by the user/CI, to limit the installation to a specific
|
||||
# subset of development dependencies.
|
||||
SLITHER_EXTRA := dev
|
||||
|
||||
# If the user selects a specific test pattern to run, set `pytest` to fail fast
|
||||
# and only run tests that match the pattern.
|
||||
# Otherwise, run all tests and enable coverage assertions, since we expect
|
||||
# complete test coverage.
|
||||
ifneq ($(TESTS),) |
||||
TEST_ARGS := -x -k $(TESTS)
|
||||
COV_ARGS :=
|
||||
else |
||||
TEST_ARGS := -n auto
|
||||
COV_ARGS := # --fail-under 100
|
||||
endif |
||||
|
||||
.PHONY: all |
||||
all: |
||||
@echo "Run my targets individually!"
|
||||
|
||||
.PHONY: dev |
||||
dev: $(VENV)/pyvenv.cfg |
||||
|
||||
.PHONY: run |
||||
run: $(VENV)/pyvenv.cfg |
||||
@. $(VENV_BIN)/activate && slither $(ARGS)
|
||||
|
||||
$(VENV)/pyvenv.cfg: pyproject.toml |
||||
# Create our Python 3 virtual environment
|
||||
python3 -m venv env
|
||||
$(VENV_BIN)/python -m pip install --upgrade pip
|
||||
$(VENV_BIN)/python -m pip install -e .[$(SLITHER_EXTRA)]
|
||||
|
||||
.PHONY: lint |
||||
lint: $(VENV)/pyvenv.cfg |
||||
. $(VENV_BIN)/activate && \
|
||||
black --check . && \
|
||||
pylint $(PY_MODULE) $(TEST_MODULE)
|
||||
# ruff $(ALL_PY_SRCS) && \
|
||||
# mypy $(PY_MODULE) &&
|
||||
|
||||
.PHONY: reformat |
||||
reformat: |
||||
. $(VENV_BIN)/activate && \
|
||||
black .
|
||||
|
||||
.PHONY: test tests |
||||
test tests: $(VENV)/pyvenv.cfg |
||||
. $(VENV_BIN)/activate && \
|
||||
pytest --cov=$(PY_MODULE) $(T) $(TEST_ARGS) && \
|
||||
python -m coverage report -m $(COV_ARGS)
|
||||
|
||||
.PHONY: doc |
||||
doc: $(VENV)/pyvenv.cfg |
||||
. $(VENV_BIN)/activate && \
|
||||
PDOC_ALLOW_EXEC=1 pdoc -o html slither '!slither.tools'
|
||||
|
||||
.PHONY: package |
||||
package: $(VENV)/pyvenv.cfg |
||||
. $(VENV_BIN)/activate && \
|
||||
python3 -m build
|
||||
|
||||
.PHONY: edit |
||||
edit: |
||||
$(EDITOR) $(ALL_PY_SRCS)
|
@ -1,3 +1,9 @@ |
||||
contract A{ |
||||
pragma solidity 0.8.19; |
||||
|
||||
error RevertIt(); |
||||
|
||||
contract Example { |
||||
function reverts() external pure { |
||||
revert RevertIt(); |
||||
} |
||||
} |
@ -1,5 +1,16 @@ |
||||
import "./a.sol"; |
||||
|
||||
contract B is A{ |
||||
pragma solidity 0.8.19; |
||||
|
||||
enum B { |
||||
a, |
||||
b |
||||
} |
||||
|
||||
contract T { |
||||
Example e = new Example(); |
||||
function b() public returns(uint) { |
||||
B b = B.a; |
||||
return 4; |
||||
} |
||||
} |
@ -0,0 +1,95 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
### Test slither-interface |
||||
|
||||
DIR_TESTS="tests/tools/interface" |
||||
|
||||
solc-select use 0.8.19 --always-install |
||||
|
||||
#Test 1 - Etherscan target |
||||
slither-interface WETH9 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 |
||||
DIFF=$(diff crytic-export/interfaces/IWETH9.sol "$DIR_TESTS/test_1.sol" --strip-trailing-cr) |
||||
if [ "$DIFF" != "" ] |
||||
then |
||||
echo "slither-interface test 1 failed" |
||||
cat "crytic-export/interfaces/IWETH9.sol" |
||||
echo "" |
||||
cat "$DIR_TESTS/test_1.sol" |
||||
exit 255 |
||||
fi |
||||
|
||||
|
||||
#Test 2 - Local file target |
||||
slither-interface Mock tests/tools/interface/ContractMock.sol |
||||
DIFF=$(diff crytic-export/interfaces/IMock.sol "$DIR_TESTS/test_2.sol" --strip-trailing-cr) |
||||
if [ "$DIFF" != "" ] |
||||
then |
||||
echo "slither-interface test 2 failed" |
||||
cat "crytic-export/interfaces/IMock.sol" |
||||
echo "" |
||||
cat "$DIR_TESTS/test_2.sol" |
||||
exit 255 |
||||
fi |
||||
|
||||
|
||||
#Test 3 - unroll structs |
||||
slither-interface Mock tests/tools/interface/ContractMock.sol --unroll-structs |
||||
DIFF=$(diff crytic-export/interfaces/IMock.sol "$DIR_TESTS/test_3.sol" --strip-trailing-cr) |
||||
if [ "$DIFF" != "" ] |
||||
then |
||||
echo "slither-interface test 3 failed" |
||||
cat "crytic-export/interfaces/IMock.sol" |
||||
echo "" |
||||
cat "$DIR_TESTS/test_3.sol" |
||||
exit 255 |
||||
fi |
||||
|
||||
#Test 4 - exclude structs |
||||
slither-interface Mock tests/tools/interface/ContractMock.sol --exclude-structs |
||||
DIFF=$(diff crytic-export/interfaces/IMock.sol "$DIR_TESTS/test_4.sol" --strip-trailing-cr) |
||||
if [ "$DIFF" != "" ] |
||||
then |
||||
echo "slither-interface test 4 failed" |
||||
cat "crytic-export/interfaces/IMock.sol" |
||||
echo "" |
||||
cat "$DIR_TESTS/test_4.sol" |
||||
exit 255 |
||||
fi |
||||
|
||||
#Test 5 - exclude errors |
||||
slither-interface Mock tests/tools/interface/ContractMock.sol --exclude-errors |
||||
DIFF=$(diff crytic-export/interfaces/IMock.sol "$DIR_TESTS/test_5.sol" --strip-trailing-cr) |
||||
if [ "$DIFF" != "" ] |
||||
then |
||||
echo "slither-interface test 5 failed" |
||||
cat "crytic-export/interfaces/IMock.sol" |
||||
echo "" |
||||
cat "$DIR_TESTS/test_5.sol" |
||||
exit 255 |
||||
fi |
||||
|
||||
#Test 6 - exclude enums |
||||
slither-interface Mock tests/tools/interface/ContractMock.sol --exclude-enums |
||||
DIFF=$(diff crytic-export/interfaces/IMock.sol "$DIR_TESTS/test_6.sol" --strip-trailing-cr) |
||||
if [ "$DIFF" != "" ] |
||||
then |
||||
echo "slither-interface test 6 failed" |
||||
cat "crytic-export/interfaces/IMock.sol" |
||||
echo "" |
||||
cat "$DIR_TESTS/test_6.sol" |
||||
exit 255 |
||||
fi |
||||
|
||||
#Test 7 - exclude events |
||||
slither-interface Mock tests/tools/interface/ContractMock.sol --exclude-events |
||||
DIFF=$(diff crytic-export/interfaces/IMock.sol "$DIR_TESTS/test_7.sol" --strip-trailing-cr) |
||||
if [ "$DIFF" != "" ] |
||||
then |
||||
echo "slither-interface test 7 failed" |
||||
cat "crytic-export/interfaces/IMock.sol" |
||||
echo "" |
||||
cat "$DIR_TESTS/test_7.sol" |
||||
exit 255 |
||||
fi |
||||
|
||||
rm -r crytic-export |
@ -1 +1,4 @@ |
||||
""" |
||||
.. include:: ../README.md |
||||
""" |
||||
from .slither import Slither |
||||
|
@ -0,0 +1,104 @@ |
||||
""" |
||||
Module detecting usage of more than one dynamic type in abi.encodePacked() arguments which could lead to collision |
||||
""" |
||||
|
||||
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification |
||||
from slither.core.declarations.solidity_variables import SolidityFunction |
||||
from slither.slithir.operations import SolidityCall |
||||
from slither.analyses.data_dependency.data_dependency import is_tainted |
||||
from slither.core.solidity_types import ElementaryType |
||||
from slither.core.solidity_types import ArrayType |
||||
|
||||
|
||||
def _is_dynamic_type(arg): |
||||
""" |
||||
Args: |
||||
arg (function argument) |
||||
Returns: |
||||
Bool |
||||
""" |
||||
if isinstance(arg.type, ElementaryType) and (arg.type.name in ["string", "bytes"]): |
||||
return True |
||||
if isinstance(arg.type, ArrayType) and arg.type.length is None: |
||||
return True |
||||
|
||||
return False |
||||
|
||||
|
||||
def _detect_abi_encodePacked_collision(contract): |
||||
""" |
||||
Args: |
||||
contract (Contract) |
||||
Returns: |
||||
list((Function), (list (Node))) |
||||
""" |
||||
ret = [] |
||||
# pylint: disable=too-many-nested-blocks |
||||
for f in contract.functions_and_modifiers_declared: |
||||
for n in f.nodes: |
||||
for ir in n.irs: |
||||
if isinstance(ir, SolidityCall) and ir.function == SolidityFunction( |
||||
"abi.encodePacked()" |
||||
): |
||||
dynamic_type_count = 0 |
||||
for arg in ir.arguments: |
||||
if is_tainted(arg, contract) and _is_dynamic_type(arg): |
||||
dynamic_type_count += 1 |
||||
elif dynamic_type_count > 1: |
||||
ret.append((f, n)) |
||||
dynamic_type_count = 0 |
||||
else: |
||||
dynamic_type_count = 0 |
||||
if dynamic_type_count > 1: |
||||
ret.append((f, n)) |
||||
return ret |
||||
|
||||
|
||||
class EncodePackedCollision(AbstractDetector): |
||||
""" |
||||
Detect usage of more than one dynamic type in abi.encodePacked() arguments which could to collision |
||||
""" |
||||
|
||||
ARGUMENT = "encode-packed-collision" |
||||
HELP = "ABI encodePacked Collision" |
||||
IMPACT = DetectorClassification.HIGH |
||||
CONFIDENCE = DetectorClassification.HIGH |
||||
|
||||
WIKI = ( |
||||
"https://github.com/crytic/slither/wiki/Detector-Documentation#abi-encodePacked-collision" |
||||
) |
||||
|
||||
WIKI_TITLE = "ABI encodePacked Collision" |
||||
WIKI_DESCRIPTION = """Detect collision due to dynamic type usages in `abi.encodePacked`""" |
||||
|
||||
WIKI_EXPLOIT_SCENARIO = """ |
||||
```solidity |
||||
contract Sign { |
||||
function get_hash_for_signature(string name, string doc) external returns(bytes32) { |
||||
return keccak256(abi.encodePacked(name, doc)); |
||||
} |
||||
} |
||||
``` |
||||
Bob calls `get_hash_for_signature` with (`bob`, `This is the content`). The hash returned is used as an ID. |
||||
Eve creates a collision with the ID using (`bo`, `bThis is the content`) and compromises the system. |
||||
""" |
||||
WIKI_RECOMMENDATION = """Do not use more than one dynamic type in `abi.encodePacked()` |
||||
(see the [Solidity documentation](https://solidity.readthedocs.io/en/v0.5.10/abi-spec.html?highlight=abi.encodePacked#non-standard-packed-modeDynamic)). |
||||
Use `abi.encode()`, preferably.""" |
||||
|
||||
def _detect(self): |
||||
"""Detect usage of more than one dynamic type in abi.encodePacked(..) arguments which could lead to collision""" |
||||
results = [] |
||||
for c in self.compilation_unit.contracts: |
||||
values = _detect_abi_encodePacked_collision(c) |
||||
for func, node in values: |
||||
info = [ |
||||
func, |
||||
" calls abi.encodePacked() with multiple dynamic arguments:\n\t- ", |
||||
node, |
||||
"\n", |
||||
] |
||||
json = self.generate_result(info) |
||||
results.append(json) |
||||
|
||||
return results |
@ -0,0 +1,223 @@ |
||||
from typing import List |
||||
|
||||
from slither.core.declarations import Contract, Structure, Enum |
||||
from slither.core.declarations.using_for_top_level import UsingForTopLevel |
||||
from slither.core.solidity_types import ( |
||||
UserDefinedType, |
||||
Type, |
||||
ElementaryType, |
||||
TypeAlias, |
||||
MappingType, |
||||
ArrayType, |
||||
) |
||||
from slither.core.solidity_types.elementary_type import Uint, Int, Byte |
||||
from slither.detectors.abstract_detector import ( |
||||
AbstractDetector, |
||||
DetectorClassification, |
||||
DETECTOR_INFO, |
||||
) |
||||
from slither.utils.output import Output |
||||
|
||||
|
||||
def _is_correctly_used(type_: Type, library: Contract) -> bool: |
||||
""" |
||||
Checks if a `using library for type_` statement is used correctly (that is, does library contain any function |
||||
with type_ as the first argument). |
||||
""" |
||||
for f in library.functions: |
||||
if len(f.parameters) == 0: |
||||
continue |
||||
if f.parameters[0].type and not _implicitly_convertible_to(type_, f.parameters[0].type): |
||||
continue |
||||
return True |
||||
return False |
||||
|
||||
|
||||
def _implicitly_convertible_to(type1: Type, type2: Type) -> bool: |
||||
""" |
||||
Returns True if type1 may be implicitly converted to type2. |
||||
""" |
||||
if isinstance(type1, TypeAlias) or isinstance(type2, TypeAlias): |
||||
if isinstance(type1, TypeAlias) and isinstance(type2, TypeAlias): |
||||
return type1.type == type2.type |
||||
return False |
||||
|
||||
if isinstance(type1, UserDefinedType) and isinstance(type2, UserDefinedType): |
||||
if isinstance(type1.type, Contract) and isinstance(type2.type, Contract): |
||||
return _implicitly_convertible_to_for_contracts(type1.type, type2.type) |
||||
|
||||
if isinstance(type1.type, Structure) and isinstance(type2.type, Structure): |
||||
return type1.type.canonical_name == type2.type.canonical_name |
||||
|
||||
if isinstance(type1.type, Enum) and isinstance(type2.type, Enum): |
||||
return type1.type.canonical_name == type2.type.canonical_name |
||||
|
||||
if isinstance(type1, ElementaryType) and isinstance(type2, ElementaryType): |
||||
return _implicitly_convertible_to_for_elementary_types(type1, type2) |
||||
|
||||
if isinstance(type1, MappingType) and isinstance(type2, MappingType): |
||||
return _implicitly_convertible_to_for_mappings(type1, type2) |
||||
|
||||
if isinstance(type1, ArrayType) and isinstance(type2, ArrayType): |
||||
return _implicitly_convertible_to_for_arrays(type1, type2) |
||||
|
||||
return False |
||||
|
||||
|
||||
def _implicitly_convertible_to_for_arrays(type1: ArrayType, type2: ArrayType) -> bool: |
||||
""" |
||||
Returns True if type1 may be implicitly converted to type2. |
||||
""" |
||||
return _implicitly_convertible_to(type1.type, type2.type) |
||||
|
||||
|
||||
def _implicitly_convertible_to_for_mappings(type1: MappingType, type2: MappingType) -> bool: |
||||
""" |
||||
Returns True if type1 may be implicitly converted to type2. |
||||
""" |
||||
return type1.type_from == type2.type_from and type1.type_to == type2.type_to |
||||
|
||||
|
||||
def _implicitly_convertible_to_for_elementary_types( |
||||
type1: ElementaryType, type2: ElementaryType |
||||
) -> bool: |
||||
""" |
||||
Returns True if type1 may be implicitly converted to type2. |
||||
""" |
||||
if type1.type == "bool" and type2.type == "bool": |
||||
return True |
||||
if type1.type == "string" and type2.type == "string": |
||||
return True |
||||
if type1.type == "bytes" and type2.type == "bytes": |
||||
return True |
||||
if type1.type == "address" and type2.type == "address": |
||||
return _implicitly_convertible_to_for_addresses(type1, type2) |
||||
if type1.type in Uint and type2.type in Uint: |
||||
return _implicitly_convertible_to_for_uints(type1, type2) |
||||
if type1.type in Int and type2.type in Int: |
||||
return _implicitly_convertible_to_for_ints(type1, type2) |
||||
if ( |
||||
type1.type != "bytes" |
||||
and type2.type != "bytes" |
||||
and type1.type in Byte |
||||
and type2.type in Byte |
||||
): |
||||
return _implicitly_convertible_to_for_bytes(type1, type2) |
||||
return False |
||||
|
||||
|
||||
def _implicitly_convertible_to_for_bytes(type1: ElementaryType, type2: ElementaryType) -> bool: |
||||
""" |
||||
Returns True if type1 may be implicitly converted to type2 assuming they are both bytes. |
||||
""" |
||||
assert type1.type in Byte and type2.type in Byte |
||||
assert type1.size is not None |
||||
assert type2.size is not None |
||||
|
||||
return type1.size <= type2.size |
||||
|
||||
|
||||
def _implicitly_convertible_to_for_addresses(type1: ElementaryType, type2: ElementaryType) -> bool: |
||||
""" |
||||
Returns True if type1 may be implicitly converted to type2 assuming they are both addresses. |
||||
""" |
||||
assert type1.type == "address" and type2.type == "address" |
||||
# payable attribute to be implemented; for now, always return True |
||||
return True |
||||
|
||||
|
||||
def _implicitly_convertible_to_for_ints(type1: ElementaryType, type2: ElementaryType) -> bool: |
||||
""" |
||||
Returns True if type1 may be implicitly converted to type2 assuming they are both ints. |
||||
""" |
||||
assert type1.type in Int and type2.type in Int |
||||
assert type1.size is not None |
||||
assert type2.size is not None |
||||
|
||||
return type1.size <= type2.size |
||||
|
||||
|
||||
def _implicitly_convertible_to_for_uints(type1: ElementaryType, type2: ElementaryType) -> bool: |
||||
""" |
||||
Returns True if type1 may be implicitly converted to type2 assuming they are both uints. |
||||
""" |
||||
assert type1.type in Uint and type2.type in Uint |
||||
assert type1.size is not None |
||||
assert type2.size is not None |
||||
|
||||
return type1.size <= type2.size |
||||
|
||||
|
||||
def _implicitly_convertible_to_for_contracts(contract1: Contract, contract2: Contract) -> bool: |
||||
""" |
||||
Returns True if contract1 may be implicitly converted to contract2. |
||||
""" |
||||
return contract1 == contract2 or contract2 in contract1.inheritance |
||||
|
||||
|
||||
class IncorrectUsingFor(AbstractDetector): |
||||
""" |
||||
Detector for incorrect using-for statement usage. |
||||
""" |
||||
|
||||
ARGUMENT = "incorrect-using-for" |
||||
HELP = "Detects using-for statement usage when no function from a given library matches a given type" |
||||
IMPACT = DetectorClassification.INFORMATIONAL |
||||
CONFIDENCE = DetectorClassification.HIGH |
||||
|
||||
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-using-for-usage" |
||||
|
||||
WIKI_TITLE = "Incorrect usage of using-for statement" |
||||
WIKI_DESCRIPTION = ( |
||||
"In Solidity, it is possible to use libraries for certain types, by the `using-for` statement " |
||||
"(`using <library> for <type>`). However, the Solidity compiler doesn't check whether a given " |
||||
"library has at least one function matching a given type. If it doesn't, such a statement has " |
||||
"no effect and may be confusing. " |
||||
) |
||||
|
||||
# region wiki_exploit_scenario |
||||
WIKI_EXPLOIT_SCENARIO = """ |
||||
```solidity |
||||
library L { |
||||
function f(bool) public pure {} |
||||
} |
||||
|
||||
using L for uint; |
||||
``` |
||||
Such a code will compile despite the fact that `L` has no function with `uint` as its first argument.""" |
||||
# endregion wiki_exploit_scenario |
||||
WIKI_RECOMMENDATION = ( |
||||
"Make sure that the libraries used in `using-for` statements have at least one function " |
||||
"matching a type used in these statements. " |
||||
) |
||||
|
||||
def _append_result( |
||||
self, results: List[Output], uf: UsingForTopLevel, type_: Type, library: Contract |
||||
) -> None: |
||||
info: DETECTOR_INFO = [ |
||||
f"using-for statement at {uf.source_mapping} is incorrect - no matching function for {type_} found in ", |
||||
library, |
||||
".\n", |
||||
] |
||||
res = self.generate_result(info) |
||||
results.append(res) |
||||
|
||||
def _detect(self) -> List[Output]: |
||||
results: List[Output] = [] |
||||
|
||||
for uf in self.compilation_unit.using_for_top_level: |
||||
# UsingForTopLevel.using_for is a dict with a single entry, which is mapped to a list of functions/libraries |
||||
# the following code extracts the type from using-for and skips using-for statements with functions |
||||
type_ = list(uf.using_for.keys())[0] |
||||
for lib_or_fcn in uf.using_for[type_]: |
||||
# checking for using-for with functions is already performed by the compiler; we only consider libraries |
||||
if isinstance(lib_or_fcn, UserDefinedType): |
||||
lib_or_fcn_type = lib_or_fcn.type |
||||
if ( |
||||
isinstance(type_, Type) |
||||
and isinstance(lib_or_fcn_type, Contract) |
||||
and not _is_correctly_used(type_, lib_or_fcn_type) |
||||
): |
||||
self._append_result(results, uf, type_, lib_or_fcn_type) |
||||
|
||||
return results |
@ -0,0 +1,105 @@ |
||||
import argparse |
||||
import logging |
||||
from pathlib import Path |
||||
|
||||
from crytic_compile import cryticparser |
||||
|
||||
from slither import Slither |
||||
from slither.utils.code_generation import generate_interface |
||||
|
||||
logging.basicConfig() |
||||
logger = logging.getLogger("Slither-Interface") |
||||
logger.setLevel(logging.INFO) |
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace: |
||||
""" |
||||
Parse the underlying arguments for the program. |
||||
:return: Returns the arguments for the program. |
||||
""" |
||||
parser = argparse.ArgumentParser( |
||||
description="Generates code for a Solidity interface from contract", |
||||
usage=("slither-interface <ContractName> <source file or deployment address>"), |
||||
) |
||||
|
||||
parser.add_argument( |
||||
"contract_source", |
||||
help="The name of the contract (case sensitive) followed by the deployed contract address if verified on etherscan or project directory/filename for local contracts.", |
||||
nargs="+", |
||||
) |
||||
|
||||
parser.add_argument( |
||||
"--unroll-structs", |
||||
help="Whether to use structures' underlying types instead of the user-defined type", |
||||
default=False, |
||||
action="store_true", |
||||
) |
||||
|
||||
parser.add_argument( |
||||
"--exclude-events", |
||||
help="Excludes event signatures in the interface", |
||||
default=False, |
||||
action="store_true", |
||||
) |
||||
|
||||
parser.add_argument( |
||||
"--exclude-errors", |
||||
help="Excludes custom error signatures in the interface", |
||||
default=False, |
||||
action="store_true", |
||||
) |
||||
|
||||
parser.add_argument( |
||||
"--exclude-enums", |
||||
help="Excludes enum definitions in the interface", |
||||
default=False, |
||||
action="store_true", |
||||
) |
||||
|
||||
parser.add_argument( |
||||
"--exclude-structs", |
||||
help="Exclude struct definitions in the interface", |
||||
default=False, |
||||
action="store_true", |
||||
) |
||||
|
||||
cryticparser.init(parser) |
||||
|
||||
return parser.parse_args() |
||||
|
||||
|
||||
def main() -> None: |
||||
args = parse_args() |
||||
|
||||
contract_name, target = args.contract_source |
||||
slither = Slither(target, **vars(args)) |
||||
|
||||
_contract = slither.get_contract_from_name(contract_name)[0] |
||||
|
||||
interface = generate_interface( |
||||
contract=_contract, |
||||
unroll_structs=args.unroll_structs, |
||||
include_events=not args.exclude_events, |
||||
include_errors=not args.exclude_errors, |
||||
include_enums=not args.exclude_enums, |
||||
include_structs=not args.exclude_structs, |
||||
) |
||||
|
||||
# add version pragma |
||||
interface = ( |
||||
f"pragma solidity {_contract.compilation_unit.pragma_directives[0].version};\n\n" |
||||
+ interface |
||||
) |
||||
|
||||
# write interface to file |
||||
export = Path("crytic-export", "interfaces") |
||||
export.mkdir(parents=True, exist_ok=True) |
||||
filename = f"I{contract_name}.sol" |
||||
path = Path(export, filename) |
||||
logger.info(f" Interface exported to {path}") |
||||
with open(path, "w", encoding="utf8") as f: |
||||
f.write(interface) |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
main() |
@ -0,0 +1,79 @@ |
||||
# pylint: disable=redefined-outer-name |
||||
import os |
||||
from pathlib import Path |
||||
import tempfile |
||||
import shutil |
||||
from contextlib import contextmanager |
||||
import pytest |
||||
from filelock import FileLock |
||||
from solc_select import solc_select |
||||
from slither import Slither |
||||
|
||||
|
||||
def pytest_configure(config): |
||||
"""Create a temporary directory for the tests to use.""" |
||||
if is_master(): |
||||
config.stash["shared_directory"] = tempfile.mkdtemp() |
||||
|
||||
|
||||
def pytest_unconfigure(config): |
||||
"""Remove the temporary directory after the tests are done.""" |
||||
if is_master(): |
||||
shutil.rmtree(config.stash["shared_directory"]) |
||||
|
||||
|
||||
def pytest_configure_node(node): |
||||
"""Configure each worker node with the shared directory.""" |
||||
node.workerinput["shared_directory"] = node.config.stash["shared_directory"] |
||||
|
||||
|
||||
def is_master(): |
||||
"""Returns True if the current process is the master process (which does not have a worker id).""" |
||||
return os.environ.get("PYTEST_XDIST_WORKER") is None |
||||
|
||||
|
||||
@pytest.fixture |
||||
def shared_directory(request): |
||||
"""Returns the shared directory for the current process.""" |
||||
if is_master(): |
||||
return request.config.stash["shared_directory"] |
||||
return request.config.workerinput["shared_directory"] |
||||
|
||||
|
||||
@pytest.fixture |
||||
def solc_binary_path(shared_directory): |
||||
""" |
||||
Returns the path to the solc binary for the given version. |
||||
If the binary is not installed, it will be installed. |
||||
""" |
||||
|
||||
def inner(version): |
||||
lock = FileLock(f"{shared_directory}/{version}.lock", timeout=60) |
||||
with lock: |
||||
if not solc_select.artifact_path(version).exists(): |
||||
print("Installing solc version", version) |
||||
solc_select.install_artifacts([version]) |
||||
return solc_select.artifact_path(version).as_posix() |
||||
|
||||
return inner |
||||
|
||||
|
||||
@pytest.fixture |
||||
def slither_from_source(solc_binary_path): |
||||
@contextmanager |
||||
def inner(source_code: str, solc_version: str = "0.8.19"): |
||||
"""Yields a Slither instance using source_code string and solc_version. |
||||
Creates a temporary file and compiles with solc_version. |
||||
""" |
||||
|
||||
fname = "" |
||||
try: |
||||
with tempfile.NamedTemporaryFile(mode="w", suffix=".sol", delete=False) as f: |
||||
fname = f.name |
||||
f.write(source_code) |
||||
solc_path = solc_binary_path(solc_version) |
||||
yield Slither(fname, solc=solc_path) |
||||
finally: |
||||
Path(fname).unlink() |
||||
|
||||
return inner |
@ -0,0 +1,18 @@ |
||||
Function A.bad3() (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#39-41) trigger an abi encoding bug: |
||||
- b = abi.encode(s) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#40) |
||||
|
||||
Function A.bad0() (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#21-23) trigger an abi encoding bug: |
||||
- this.bad0_external(bad_arr) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#22) |
||||
|
||||
Function A.bad4() (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#44-46) trigger an abi encoding bug: |
||||
- event1_bad(bad_arr) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#45) |
||||
|
||||
Function A.bad2() (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#34-36) trigger an abi encoding bug: |
||||
- b = abi.encode(bad_arr) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#35) |
||||
|
||||
Function A.bad1(A.S[3]) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#29-31) trigger an abi encoding bug: |
||||
- this.bad1_external(s) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#30) |
||||
|
||||
Function A.bad5() (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#49-51) trigger an abi encoding bug: |
||||
- event2_bad(s) (tests/e2e/detectors/test_data/abiencoderv2-array/0.4.25/storage_ABIEncoderV2_array.sol#50) |
||||
|
@ -0,0 +1,18 @@ |
||||
Function A.bad5() (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#49-51) trigger an abi encoding bug: |
||||
- event2_bad(s) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#50) |
||||
|
||||
Function A.bad0() (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#21-23) trigger an abi encoding bug: |
||||
- this.bad0_external(bad_arr) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#22) |
||||
|
||||
Function A.bad4() (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#44-46) trigger an abi encoding bug: |
||||
- event1_bad(bad_arr) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#45) |
||||
|
||||
Function A.bad2() (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#34-36) trigger an abi encoding bug: |
||||
- b = abi.encode(bad_arr) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#35) |
||||
|
||||
Function A.bad1(A.S[3]) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#29-31) trigger an abi encoding bug: |
||||
- this.bad1_external(s) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#30) |
||||
|
||||
Function A.bad3() (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#39-41) trigger an abi encoding bug: |
||||
- b = abi.encode(s) (tests/e2e/detectors/test_data/abiencoderv2-array/0.5.9/storage_ABIEncoderV2_array.sol#40) |
||||
|
@ -0,0 +1,6 @@ |
||||
C.bad4(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.4.25/arbitrary_send_erc20.sol#65-67) uses arbitrary from in transferFrom: SafeERC20.safeTransferFrom(erc20,from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.4.25/arbitrary_send_erc20.sol#66) |
||||
|
||||
C.bad1(address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.4.25/arbitrary_send_erc20.sol#35-37) uses arbitrary from in transferFrom: erc20.transferFrom(notsend,to,am) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.4.25/arbitrary_send_erc20.sol#36) |
||||
|
||||
C.bad3(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.4.25/arbitrary_send_erc20.sol#57-59) uses arbitrary from in transferFrom: erc20.safeTransferFrom(from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.4.25/arbitrary_send_erc20.sol#58) |
||||
|
@ -0,0 +1,6 @@ |
||||
C.bad4(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.5.16/arbitrary_send_erc20.sol#65-67) uses arbitrary from in transferFrom: SafeERC20.safeTransferFrom(erc20,from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.5.16/arbitrary_send_erc20.sol#66) |
||||
|
||||
C.bad3(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.5.16/arbitrary_send_erc20.sol#57-59) uses arbitrary from in transferFrom: erc20.safeTransferFrom(from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.5.16/arbitrary_send_erc20.sol#58) |
||||
|
||||
C.bad1(address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.5.16/arbitrary_send_erc20.sol#35-37) uses arbitrary from in transferFrom: erc20.transferFrom(notsend,to,am) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.5.16/arbitrary_send_erc20.sol#36) |
||||
|
@ -0,0 +1,6 @@ |
||||
C.bad1(address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.6.11/arbitrary_send_erc20.sol#35-37) uses arbitrary from in transferFrom: erc20.transferFrom(notsend,to,am) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.6.11/arbitrary_send_erc20.sol#36) |
||||
|
||||
C.bad3(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.6.11/arbitrary_send_erc20.sol#57-59) uses arbitrary from in transferFrom: erc20.safeTransferFrom(from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.6.11/arbitrary_send_erc20.sol#58) |
||||
|
||||
C.bad4(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.6.11/arbitrary_send_erc20.sol#65-67) uses arbitrary from in transferFrom: SafeERC20.safeTransferFrom(erc20,from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.6.11/arbitrary_send_erc20.sol#66) |
||||
|
@ -0,0 +1,6 @@ |
||||
C.bad4(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.7.6/arbitrary_send_erc20.sol#65-67) uses arbitrary from in transferFrom: SafeERC20.safeTransferFrom(erc20,from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.7.6/arbitrary_send_erc20.sol#66) |
||||
|
||||
C.bad3(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.7.6/arbitrary_send_erc20.sol#57-59) uses arbitrary from in transferFrom: erc20.safeTransferFrom(from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.7.6/arbitrary_send_erc20.sol#58) |
||||
|
||||
C.bad1(address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.7.6/arbitrary_send_erc20.sol#35-37) uses arbitrary from in transferFrom: erc20.transferFrom(notsend,to,am) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.7.6/arbitrary_send_erc20.sol#36) |
||||
|
@ -0,0 +1,2 @@ |
||||
T.bad(address) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20_inheritance.sol#11-13) uses arbitrary from in transferFrom: erc20.safeTransferFrom(from,address(0x1),90) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20_inheritance.sol#12) |
||||
|
@ -0,0 +1,6 @@ |
||||
C.bad1(address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20.sol#35-37) uses arbitrary from in transferFrom: erc20.transferFrom(notsend,to,am) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20.sol#36) |
||||
|
||||
C.bad3(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20.sol#57-59) uses arbitrary from in transferFrom: erc20.safeTransferFrom(from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20.sol#58) |
||||
|
||||
C.bad4(address,address,uint256) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20.sol#65-67) uses arbitrary from in transferFrom: SafeERC20.safeTransferFrom(erc20,from,to,amount) (tests/e2e/detectors/test_data/arbitrary-send-erc20/0.8.0/arbitrary_send_erc20.sol#66) |
||||
|
@ -0,0 +1,8 @@ |
||||
C.int_transferFrom(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#42-45) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#44) |
||||
|
||||
C.bad3(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#47-50) uses arbitrary from in transferFrom in combination with permit: erc20.safeTransferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#49) |
||||
|
||||
C.bad4(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#52-55) uses arbitrary from in transferFrom in combination with permit: SafeERC20.safeTransferFrom(erc20,from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#54) |
||||
|
||||
C.bad1(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#32-35) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.4.25/arbitrary_send_erc20_permit.sol#34) |
||||
|
@ -0,0 +1,8 @@ |
||||
C.int_transferFrom(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#42-45) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#44) |
||||
|
||||
C.bad4(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#52-55) uses arbitrary from in transferFrom in combination with permit: SafeERC20.safeTransferFrom(erc20,from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#54) |
||||
|
||||
C.bad3(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#47-50) uses arbitrary from in transferFrom in combination with permit: erc20.safeTransferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#49) |
||||
|
||||
C.bad1(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#32-35) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.5.16/arbitrary_send_erc20_permit.sol#34) |
||||
|
@ -0,0 +1,8 @@ |
||||
C.bad3(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#47-50) uses arbitrary from in transferFrom in combination with permit: erc20.safeTransferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#49) |
||||
|
||||
C.bad4(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#52-55) uses arbitrary from in transferFrom in combination with permit: SafeERC20.safeTransferFrom(erc20,from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#54) |
||||
|
||||
C.int_transferFrom(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#42-45) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#44) |
||||
|
||||
C.bad1(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#32-35) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.6.11/arbitrary_send_erc20_permit.sol#34) |
||||
|
@ -0,0 +1,8 @@ |
||||
C.int_transferFrom(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#42-45) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#44) |
||||
|
||||
C.bad1(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#32-35) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#34) |
||||
|
||||
C.bad4(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#52-55) uses arbitrary from in transferFrom in combination with permit: SafeERC20.safeTransferFrom(erc20,from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#54) |
||||
|
||||
C.bad3(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#47-50) uses arbitrary from in transferFrom in combination with permit: erc20.safeTransferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.7.6/arbitrary_send_erc20_permit.sol#49) |
||||
|
@ -0,0 +1,8 @@ |
||||
C.bad3(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#47-50) uses arbitrary from in transferFrom in combination with permit: erc20.safeTransferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#49) |
||||
|
||||
C.bad4(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#52-55) uses arbitrary from in transferFrom in combination with permit: SafeERC20.safeTransferFrom(erc20,from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#54) |
||||
|
||||
C.int_transferFrom(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#42-45) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#44) |
||||
|
||||
C.bad1(address,uint256,uint256,uint8,bytes32,bytes32,address) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#32-35) uses arbitrary from in transferFrom in combination with permit: erc20.transferFrom(from,to,value) (tests/e2e/detectors/test_data/arbitrary-send-erc20-permit/0.8.0/arbitrary_send_erc20_permit.sol#34) |
||||
|
@ -0,0 +1,8 @@ |
||||
Test.indirect() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.4.25/arbitrary_send_eth.sol#19-21) sends eth to arbitrary user |
||||
Dangerous calls: |
||||
- destination.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.4.25/arbitrary_send_eth.sol#20) |
||||
|
||||
Test.direct() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.4.25/arbitrary_send_eth.sol#11-13) sends eth to arbitrary user |
||||
Dangerous calls: |
||||
- msg.sender.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.4.25/arbitrary_send_eth.sol#12) |
||||
|
@ -0,0 +1,8 @@ |
||||
Test.direct() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.5.16/arbitrary_send_eth.sol#11-13) sends eth to arbitrary user |
||||
Dangerous calls: |
||||
- msg.sender.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.5.16/arbitrary_send_eth.sol#12) |
||||
|
||||
Test.indirect() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.5.16/arbitrary_send_eth.sol#19-21) sends eth to arbitrary user |
||||
Dangerous calls: |
||||
- destination.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.5.16/arbitrary_send_eth.sol#20) |
||||
|
@ -0,0 +1,8 @@ |
||||
Test.indirect() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#19-21) sends eth to arbitrary user |
||||
Dangerous calls: |
||||
- destination.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#20) |
||||
|
||||
Test.direct() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#11-13) sends eth to arbitrary user |
||||
Dangerous calls: |
||||
- msg.sender.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.6.11/arbitrary_send_eth.sol#12) |
||||
|
@ -0,0 +1,8 @@ |
||||
Test.direct() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#11-13) sends eth to arbitrary user |
||||
Dangerous calls: |
||||
- msg.sender.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#12) |
||||
|
||||
Test.indirect() (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#19-21) sends eth to arbitrary user |
||||
Dangerous calls: |
||||
- destination.send(address(this).balance) (tests/e2e/detectors/test_data/arbitrary-send-eth/0.7.6/arbitrary_send_eth.sol#20) |
||||
|
@ -0,0 +1,12 @@ |
||||
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#39)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#25-28)which only takes arrays by value |
||||
|
||||
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#39)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#21-23)which only takes arrays by value |
||||
|
||||
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#2)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#21-23)which only takes arrays by value |
||||
|
||||
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#2)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#25-28)which only takes arrays by value |
||||
|
||||
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#11)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#25-28)which only takes arrays by value |
||||
|
||||
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#11)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#21-23)which only takes arrays by value |
||||
|
@ -0,0 +1,12 @@ |
||||
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#39)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#25-28)which only takes arrays by value |
||||
|
||||
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#39)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#21-23)which only takes arrays by value |
||||
|
||||
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#2)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#21-23)which only takes arrays by value |
||||
|
||||
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#2)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#25-28)which only takes arrays by value |
||||
|
||||
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#11)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#25-28)which only takes arrays by value |
||||
|
||||
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#11)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#21-23)which only takes arrays by value |
||||
|
@ -0,0 +1,12 @@ |
||||
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#39)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#25-28)which only takes arrays by value |
||||
|
||||
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#39)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#21-23)which only takes arrays by value |
||||
|
||||
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#2)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#21-23)which only takes arrays by value |
||||
|
||||
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#2)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#25-28)which only takes arrays by value |
||||
|
||||
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#11)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#25-28)which only takes arrays by value |
||||
|
||||
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#11)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#21-23)which only takes arrays by value |
||||
|
@ -0,0 +1,12 @@ |
||||
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#39)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#25-28)which only takes arrays by value |
||||
|
||||
D.f() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#42-48) passes array D.x (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#39)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#21-23)which only takes arrays by value |
||||
|
||||
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#2)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#21-23)which only takes arrays by value |
||||
|
||||
C.f() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#4-8) passes array C.x (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#2)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#25-28)which only takes arrays by value |
||||
|
||||
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#11)by reference to C.setByValueAndReturn(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#25-28)which only takes arrays by value |
||||
|
||||
C.g() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#10-15) passes array C.g().y (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#11)by reference to C.setByValue(uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#21-23)which only takes arrays by value |
||||
|
@ -0,0 +1,9 @@ |
||||
ArrayLengthAssignment (tests/e2e/detectors/test_data/controlled-array-length/0.4.25/array_length_assignment.sol#1-46) contract sets array length with a user-controlled value: |
||||
- b.subStruct.x.length = param + 1 (tests/e2e/detectors/test_data/controlled-array-length/0.4.25/array_length_assignment.sol#41) |
||||
|
||||
ArrayLengthAssignment (tests/e2e/detectors/test_data/controlled-array-length/0.4.25/array_length_assignment.sol#1-46) contract sets array length with a user-controlled value: |
||||
- a.x.length = param (tests/e2e/detectors/test_data/controlled-array-length/0.4.25/array_length_assignment.sol#36) |
||||
|
||||
ArrayLengthAssignment (tests/e2e/detectors/test_data/controlled-array-length/0.4.25/array_length_assignment.sol#1-46) contract sets array length with a user-controlled value: |
||||
- arr.length = param (tests/e2e/detectors/test_data/controlled-array-length/0.4.25/array_length_assignment.sol#26) |
||||
|
@ -0,0 +1,9 @@ |
||||
ArrayLengthAssignment (tests/e2e/detectors/test_data/controlled-array-length/0.5.16/array_length_assignment.sol#1-46) contract sets array length with a user-controlled value: |
||||
- b.subStruct.x.length = param + 1 (tests/e2e/detectors/test_data/controlled-array-length/0.5.16/array_length_assignment.sol#41) |
||||
|
||||
ArrayLengthAssignment (tests/e2e/detectors/test_data/controlled-array-length/0.5.16/array_length_assignment.sol#1-46) contract sets array length with a user-controlled value: |
||||
- a.x.length = param (tests/e2e/detectors/test_data/controlled-array-length/0.5.16/array_length_assignment.sol#36) |
||||
|
||||
ArrayLengthAssignment (tests/e2e/detectors/test_data/controlled-array-length/0.5.16/array_length_assignment.sol#1-46) contract sets array length with a user-controlled value: |
||||
- arr.length = param (tests/e2e/detectors/test_data/controlled-array-length/0.5.16/array_length_assignment.sol#26) |
||||
|
@ -0,0 +1,3 @@ |
||||
GetCode.at(address) (tests/e2e/detectors/test_data/assembly/0.4.25/inline_assembly_contract.sol#6-20) uses assembly |
||||
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.4.25/inline_assembly_contract.sol#7-20) |
||||
|
@ -0,0 +1,6 @@ |
||||
VectorSum.sumPureAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.4.25/inline_assembly_library.sol#25-47) uses assembly |
||||
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.4.25/inline_assembly_library.sol#26-47) |
||||
|
||||
VectorSum.sumAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.4.25/inline_assembly_library.sol#16-22) uses assembly |
||||
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.4.25/inline_assembly_library.sol#18-21) |
||||
|
@ -0,0 +1,3 @@ |
||||
GetCode.at(address) (tests/e2e/detectors/test_data/assembly/0.5.16/inline_assembly_contract.sol#6-20) uses assembly |
||||
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.5.16/inline_assembly_contract.sol#7-19) |
||||
|
@ -0,0 +1,6 @@ |
||||
VectorSum.sumAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.5.16/inline_assembly_library.sol#16-22) uses assembly |
||||
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.5.16/inline_assembly_library.sol#18-20) |
||||
|
||||
VectorSum.sumPureAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.5.16/inline_assembly_library.sol#25-47) uses assembly |
||||
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.5.16/inline_assembly_library.sol#26-46) |
||||
|
@ -0,0 +1,3 @@ |
||||
GetCode.at(address) (tests/e2e/detectors/test_data/assembly/0.6.11/inline_assembly_contract.sol#4-18) uses assembly |
||||
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.6.11/inline_assembly_contract.sol#5-17) |
||||
|
@ -0,0 +1,6 @@ |
||||
VectorSum.sumAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.6.11/inline_assembly_library.sol#14-20) uses assembly |
||||
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.6.11/inline_assembly_library.sol#16-18) |
||||
|
||||
VectorSum.sumPureAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.6.11/inline_assembly_library.sol#23-45) uses assembly |
||||
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.6.11/inline_assembly_library.sol#24-44) |
||||
|
@ -0,0 +1,3 @@ |
||||
GetCode.at(address) (tests/e2e/detectors/test_data/assembly/0.7.6/inline_assembly_contract.sol#4-18) uses assembly |
||||
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.7.6/inline_assembly_contract.sol#5-17) |
||||
|
@ -0,0 +1,6 @@ |
||||
VectorSum.sumAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.7.6/inline_assembly_library.sol#14-20) uses assembly |
||||
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.7.6/inline_assembly_library.sol#16-18) |
||||
|
||||
VectorSum.sumPureAsm(uint256[]) (tests/e2e/detectors/test_data/assembly/0.7.6/inline_assembly_library.sol#23-45) uses assembly |
||||
- INLINE ASM (tests/e2e/detectors/test_data/assembly/0.7.6/inline_assembly_library.sol#24-44) |
||||
|
@ -0,0 +1,12 @@ |
||||
A.bad2() (tests/e2e/detectors/test_data/assert-state-change/0.4.25/assert_state_change.sol#19-21) has an assert() call which possibly changes state. |
||||
-assert(bool)(bad2_callee()) (tests/e2e/detectors/test_data/assert-state-change/0.4.25/assert_state_change.sol#20) |
||||
Consider using require() or change the invariant to not modify the state. |
||||
|
||||
A.bad0() (tests/e2e/detectors/test_data/assert-state-change/0.4.25/assert_state_change.sol#6-8) has an assert() call which possibly changes state. |
||||
-assert(bool)((s_a += 1) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.4.25/assert_state_change.sol#7) |
||||
Consider using require() or change the invariant to not modify the state. |
||||
|
||||
A.bad1(uint256) (tests/e2e/detectors/test_data/assert-state-change/0.4.25/assert_state_change.sol#11-13) has an assert() call which possibly changes state. |
||||
-assert(bool)((s_a += a) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.4.25/assert_state_change.sol#12) |
||||
Consider using require() or change the invariant to not modify the state. |
||||
|
@ -0,0 +1,12 @@ |
||||
A.bad1(uint256) (tests/e2e/detectors/test_data/assert-state-change/0.5.16/assert_state_change.sol#11-13) has an assert() call which possibly changes state. |
||||
-assert(bool)((s_a += a) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.5.16/assert_state_change.sol#12) |
||||
Consider using require() or change the invariant to not modify the state. |
||||
|
||||
A.bad2() (tests/e2e/detectors/test_data/assert-state-change/0.5.16/assert_state_change.sol#19-21) has an assert() call which possibly changes state. |
||||
-assert(bool)(bad2_callee()) (tests/e2e/detectors/test_data/assert-state-change/0.5.16/assert_state_change.sol#20) |
||||
Consider using require() or change the invariant to not modify the state. |
||||
|
||||
A.bad0() (tests/e2e/detectors/test_data/assert-state-change/0.5.16/assert_state_change.sol#6-8) has an assert() call which possibly changes state. |
||||
-assert(bool)((s_a += 1) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.5.16/assert_state_change.sol#7) |
||||
Consider using require() or change the invariant to not modify the state. |
||||
|
@ -0,0 +1,12 @@ |
||||
A.bad0() (tests/e2e/detectors/test_data/assert-state-change/0.6.11/assert_state_change.sol#6-8) has an assert() call which possibly changes state. |
||||
-assert(bool)((s_a += 1) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.6.11/assert_state_change.sol#7) |
||||
Consider using require() or change the invariant to not modify the state. |
||||
|
||||
A.bad1(uint256) (tests/e2e/detectors/test_data/assert-state-change/0.6.11/assert_state_change.sol#11-13) has an assert() call which possibly changes state. |
||||
-assert(bool)((s_a += a) > 10) (tests/e2e/detectors/test_data/assert-state-change/0.6.11/assert_state_change.sol#12) |
||||
Consider using require() or change the invariant to not modify the state. |
||||
|
||||
A.bad2() (tests/e2e/detectors/test_data/assert-state-change/0.6.11/assert_state_change.sol#19-21) has an assert() call which possibly changes state. |
||||
-assert(bool)(bad2_callee()) (tests/e2e/detectors/test_data/assert-state-change/0.6.11/assert_state_change.sol#20) |
||||
Consider using require() or change the invariant to not modify the state. |
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue