mirror of https://github.com/crytic/slither
commit
c175d527ff
@ -0,0 +1,8 @@ |
||||
--- |
||||
version: 2 |
||||
updates: |
||||
- package-ecosystem: "github-actions" |
||||
directory: "/" |
||||
target-branch: "dev" |
||||
schedule: |
||||
interval: "weekly" |
@ -0,0 +1,54 @@ |
||||
name: Publish to PyPI |
||||
|
||||
on: |
||||
release: |
||||
types: [published] |
||||
|
||||
jobs: |
||||
build-release: |
||||
|
||||
runs-on: ubuntu-latest |
||||
|
||||
steps: |
||||
- uses: actions/checkout@v3 |
||||
|
||||
- name: Set up Python |
||||
uses: actions/setup-python@v4 |
||||
with: |
||||
python-version: '3.x' |
||||
|
||||
- name: Build distributions |
||||
run: | |
||||
python -m pip install --upgrade pip |
||||
python -m pip install build |
||||
python -m build |
||||
- name: Upload distributions |
||||
uses: actions/upload-artifact@v3 |
||||
with: |
||||
name: slither-dists |
||||
path: dist/ |
||||
|
||||
publish: |
||||
runs-on: ubuntu-latest |
||||
environment: release |
||||
permissions: |
||||
id-token: write # For trusted publishing + codesigning. |
||||
contents: write # For attaching signing artifacts to the release. |
||||
needs: |
||||
- build-release |
||||
steps: |
||||
- name: fetch dists |
||||
uses: actions/download-artifact@v3 |
||||
with: |
||||
name: slither-dists |
||||
path: dist/ |
||||
|
||||
- name: publish |
||||
uses: pypa/gh-action-pypi-publish@v1.8.7 |
||||
|
||||
- name: sign |
||||
uses: sigstore/gh-action-sigstore-python@v1.2.3 |
||||
with: |
||||
inputs: ./dist/*.tar.gz ./dist/*.whl |
||||
release-signing-artifacts: true |
||||
bundle-only: true |
@ -0,0 +1,221 @@ |
||||
from typing import List, Set |
||||
|
||||
from slither.core.cfg.node import Node, NodeType |
||||
from slither.core.declarations import Function |
||||
from slither.core.expressions import BinaryOperation, Identifier, MemberAccess, UnaryOperation |
||||
from slither.core.solidity_types import ArrayType |
||||
from slither.core.source_mapping.source_mapping import SourceMapping |
||||
from slither.core.variables import StateVariable |
||||
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification |
||||
from slither.slithir.operations import Length, Delete, HighLevelCall |
||||
|
||||
|
||||
class CacheArrayLength(AbstractDetector): |
||||
""" |
||||
Detects `for` loops that use `length` member of some storage array in their loop condition and don't modify it. |
||||
""" |
||||
|
||||
ARGUMENT = "cache-array-length" |
||||
HELP = ( |
||||
"Detects `for` loops that use `length` member of some storage array in their loop condition and don't " |
||||
"modify it. " |
||||
) |
||||
IMPACT = DetectorClassification.OPTIMIZATION |
||||
CONFIDENCE = DetectorClassification.HIGH |
||||
|
||||
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#cache-array-length" |
||||
|
||||
WIKI_TITLE = "Cache array length" |
||||
WIKI_DESCRIPTION = ( |
||||
"Detects `for` loops that use `length` member of some storage array in their loop condition " |
||||
"and don't modify it. " |
||||
) |
||||
WIKI_EXPLOIT_SCENARIO = """ |
||||
```solidity |
||||
contract C |
||||
{ |
||||
uint[] array; |
||||
|
||||
function f() public |
||||
{ |
||||
for (uint i = 0; i < array.length; i++) |
||||
{ |
||||
// code that does not modify length of `array` |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
Since the `for` loop in `f` doesn't modify `array.length`, it is more gas efficient to cache it in some local variable and use that variable instead, like in the following example: |
||||
|
||||
```solidity |
||||
contract C |
||||
{ |
||||
uint[] array; |
||||
|
||||
function f() public |
||||
{ |
||||
uint array_length = array.length; |
||||
for (uint i = 0; i < array_length; i++) |
||||
{ |
||||
// code that does not modify length of `array` |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
""" |
||||
WIKI_RECOMMENDATION = ( |
||||
"Cache the lengths of storage arrays if they are used and not modified in `for` loops." |
||||
) |
||||
|
||||
@staticmethod |
||||
def _is_identifier_member_access_comparison(exp: BinaryOperation) -> bool: |
||||
""" |
||||
Checks whether a BinaryOperation `exp` is an operation on Identifier and MemberAccess. |
||||
""" |
||||
return ( |
||||
isinstance(exp.expression_left, Identifier) |
||||
and isinstance(exp.expression_right, MemberAccess) |
||||
) or ( |
||||
isinstance(exp.expression_left, MemberAccess) |
||||
and isinstance(exp.expression_right, Identifier) |
||||
) |
||||
|
||||
@staticmethod |
||||
def _extract_array_from_length_member_access(exp: MemberAccess) -> StateVariable: |
||||
""" |
||||
Given a member access `exp`, it returns state array which `length` member is accessed through `exp`. |
||||
If array is not a state array or its `length` member is not referenced, it returns `None`. |
||||
""" |
||||
if exp.member_name != "length": |
||||
return None |
||||
if not isinstance(exp.expression, Identifier): |
||||
return None |
||||
if not isinstance(exp.expression.value, StateVariable): |
||||
return None |
||||
if not isinstance(exp.expression.value.type, ArrayType): |
||||
return None |
||||
return exp.expression.value |
||||
|
||||
@staticmethod |
||||
def _is_loop_referencing_array_length( |
||||
node: Node, visited: Set[Node], array: StateVariable, depth: int |
||||
) -> True: |
||||
""" |
||||
For a given loop, checks if it references `array.length` at some point. |
||||
Will also return True if `array.length` is referenced but not changed. |
||||
This may potentially generate false negatives in the detector, but it was done this way because: |
||||
- situations when array `length` is referenced but not modified in loop are rare |
||||
- checking if `array.length` is indeed modified would require much more work |
||||
""" |
||||
visited.add(node) |
||||
if node.type == NodeType.STARTLOOP: |
||||
depth += 1 |
||||
if node.type == NodeType.ENDLOOP: |
||||
depth -= 1 |
||||
if depth == 0: |
||||
return False |
||||
|
||||
# Array length may change in the following situations: |
||||
# - when `push` is called |
||||
# - when `pop` is called |
||||
# - when `delete` is called on the entire array |
||||
# - when external function call is made (instructions from internal function calls are already in |
||||
# `node.all_slithir_operations()`, so we don't need to handle internal calls separately) |
||||
if node.type == NodeType.EXPRESSION: |
||||
for op in node.all_slithir_operations(): |
||||
if isinstance(op, Length) and op.value == array: |
||||
# op accesses array.length, not necessarily modifying it |
||||
return True |
||||
if isinstance(op, Delete): |
||||
# take into account only delete entire array, since delete array[i] doesn't change `array.length` |
||||
if ( |
||||
isinstance(op.expression, UnaryOperation) |
||||
and isinstance(op.expression.expression, Identifier) |
||||
and op.expression.expression.value == array |
||||
): |
||||
return True |
||||
if isinstance(op, HighLevelCall) and not op.function.view and not op.function.pure: |
||||
return True |
||||
|
||||
for son in node.sons: |
||||
if son not in visited: |
||||
if CacheArrayLength._is_loop_referencing_array_length(son, visited, array, depth): |
||||
return True |
||||
return False |
||||
|
||||
@staticmethod |
||||
def _handle_loops(nodes: List[Node], non_optimal_array_len_usages: List[SourceMapping]) -> None: |
||||
""" |
||||
For each loop, checks if it has a comparison with `length` array member and, if it has, checks whether that |
||||
array size could potentially change in that loop. |
||||
If it cannot, the loop condition is added to `non_optimal_array_len_usages`. |
||||
There may be some false negatives here - see docs for `_is_loop_referencing_array_length` for more information. |
||||
""" |
||||
for node in nodes: |
||||
if node.type == NodeType.STARTLOOP: |
||||
if_node = node.sons[0] |
||||
if if_node.type != NodeType.IFLOOP: |
||||
continue |
||||
if not isinstance(if_node.expression, BinaryOperation): |
||||
continue |
||||
exp: BinaryOperation = if_node.expression |
||||
if not CacheArrayLength._is_identifier_member_access_comparison(exp): |
||||
continue |
||||
array: StateVariable |
||||
if isinstance(exp.expression_right, MemberAccess): |
||||
array = CacheArrayLength._extract_array_from_length_member_access( |
||||
exp.expression_right |
||||
) |
||||
else: # isinstance(exp.expression_left, MemberAccess) == True |
||||
array = CacheArrayLength._extract_array_from_length_member_access( |
||||
exp.expression_left |
||||
) |
||||
if array is None: |
||||
continue |
||||
|
||||
visited: Set[Node] = set() |
||||
if not CacheArrayLength._is_loop_referencing_array_length( |
||||
if_node, visited, array, 1 |
||||
): |
||||
non_optimal_array_len_usages.append(if_node) |
||||
|
||||
@staticmethod |
||||
def _get_non_optimal_array_len_usages_for_function(f: Function) -> List[SourceMapping]: |
||||
""" |
||||
Finds non-optimal usages of array length in loop conditions in a given function. |
||||
""" |
||||
non_optimal_array_len_usages: List[SourceMapping] = [] |
||||
CacheArrayLength._handle_loops(f.nodes, non_optimal_array_len_usages) |
||||
|
||||
return non_optimal_array_len_usages |
||||
|
||||
@staticmethod |
||||
def _get_non_optimal_array_len_usages(functions: List[Function]) -> List[SourceMapping]: |
||||
""" |
||||
Finds non-optimal usages of array length in loop conditions in given functions. |
||||
""" |
||||
non_optimal_array_len_usages: List[SourceMapping] = [] |
||||
|
||||
for f in functions: |
||||
non_optimal_array_len_usages += ( |
||||
CacheArrayLength._get_non_optimal_array_len_usages_for_function(f) |
||||
) |
||||
|
||||
return non_optimal_array_len_usages |
||||
|
||||
def _detect(self): |
||||
results = [] |
||||
|
||||
non_optimal_array_len_usages = CacheArrayLength._get_non_optimal_array_len_usages( |
||||
self.compilation_unit.functions |
||||
) |
||||
for usage in non_optimal_array_len_usages: |
||||
info = [ |
||||
"Loop condition at ", |
||||
usage, |
||||
" should use cached array length instead of referencing `length` member " |
||||
"of the storage array.\n ", |
||||
] |
||||
res = self.generate_result(info) |
||||
results.append(res) |
||||
return results |
@ -0,0 +1,35 @@ |
||||
""" |
||||
Lines of Code (LOC) printer |
||||
|
||||
Definitions: |
||||
cloc: comment lines of code containing only comments |
||||
sloc: source lines of code with no whitespace or comments |
||||
loc: all lines of code including whitespace and comments |
||||
src: source files (excluding tests and dependencies) |
||||
dep: dependency files |
||||
test: test files |
||||
""" |
||||
|
||||
from slither.printers.abstract_printer import AbstractPrinter |
||||
from slither.utils.loc import compute_loc_metrics |
||||
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), \ |
||||
and test files (TEST).""" |
||||
|
||||
WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#loc" |
||||
|
||||
def output(self, _filename: str) -> Output: |
||||
# compute loc metrics |
||||
loc = compute_loc_metrics(self.slither) |
||||
|
||||
table = loc.to_pretty_table() |
||||
txt = "Lines of Code \n" + str(table) |
||||
self.info(txt) |
||||
res = self.generate_output(txt) |
||||
res.add_pretty_table(table, "Code Lines") |
||||
return res |
@ -0,0 +1,21 @@ |
||||
# Slither-interface |
||||
|
||||
Generates code for a Solidity interface from contract |
||||
|
||||
## Usage |
||||
|
||||
Run `slither-interface <ContractName> <source file or deployment address>`. |
||||
|
||||
## CLI Interface |
||||
```shell |
||||
positional arguments: |
||||
contract_source The name of the contract (case sensitive) followed by the deployed contract address if verified on etherscan or project directory/filename for local contracts. |
||||
|
||||
optional arguments: |
||||
-h, --help show this help message and exit |
||||
--unroll-structs Whether to use structures' underlying types instead of the user-defined type |
||||
--exclude-events Excludes event signatures in the interface |
||||
--exclude-errors Excludes custom error signatures in the interface |
||||
--exclude-enums Excludes enum definitions in the interface |
||||
--exclude-structs Exclude struct definitions in the interface |
||||
``` |
@ -0,0 +1,105 @@ |
||||
from dataclasses import dataclass, field |
||||
from pathlib import Path |
||||
from typing import List, Tuple |
||||
|
||||
from slither import Slither |
||||
from slither.utils.myprettytable import MyPrettyTable |
||||
from slither.utils.tests_pattern import is_test_file |
||||
|
||||
|
||||
@dataclass |
||||
class LoCInfo: |
||||
loc: int = 0 |
||||
sloc: int = 0 |
||||
cloc: int = 0 |
||||
|
||||
def total(self) -> int: |
||||
return self.loc + self.sloc + self.cloc |
||||
|
||||
|
||||
@dataclass |
||||
class LoC: |
||||
src: LoCInfo = field(default_factory=LoCInfo) |
||||
dep: LoCInfo = field(default_factory=LoCInfo) |
||||
test: LoCInfo = field(default_factory=LoCInfo) |
||||
|
||||
def to_pretty_table(self) -> MyPrettyTable: |
||||
table = MyPrettyTable(["", "src", "dep", "test"]) |
||||
|
||||
table.add_row(["loc", str(self.src.loc), str(self.dep.loc), str(self.test.loc)]) |
||||
table.add_row(["sloc", str(self.src.sloc), str(self.dep.sloc), str(self.test.sloc)]) |
||||
table.add_row(["cloc", str(self.src.cloc), str(self.dep.cloc), str(self.test.cloc)]) |
||||
table.add_row( |
||||
["Total", str(self.src.total()), str(self.dep.total()), str(self.test.total())] |
||||
) |
||||
return table |
||||
|
||||
|
||||
def count_lines(contract_lines: List[str]) -> Tuple[int, int, int]: |
||||
"""Function to count and classify the lines of code in a contract. |
||||
Args: |
||||
contract_lines: list(str) representing the lines of a contract. |
||||
Returns: |
||||
tuple(int, int, int) representing (cloc, sloc, loc) |
||||
""" |
||||
multiline_comment = False |
||||
cloc = 0 |
||||
sloc = 0 |
||||
loc = 0 |
||||
|
||||
for line in contract_lines: |
||||
loc += 1 |
||||
stripped_line = line.strip() |
||||
if not multiline_comment: |
||||
if stripped_line.startswith("//"): |
||||
cloc += 1 |
||||
elif "/*" in stripped_line: |
||||
# Account for case where /* is followed by */ on the same line. |
||||
# If it is, then multiline_comment does not need to be set to True |
||||
start_idx = stripped_line.find("/*") |
||||
end_idx = stripped_line.find("*/", start_idx + 2) |
||||
if end_idx == -1: |
||||
multiline_comment = True |
||||
cloc += 1 |
||||
elif stripped_line: |
||||
sloc += 1 |
||||
else: |
||||
cloc += 1 |
||||
if "*/" in stripped_line: |
||||
multiline_comment = False |
||||
|
||||
return cloc, sloc, loc |
||||
|
||||
|
||||
def _update_lines(loc_info: LoCInfo, lines: list) -> None: |
||||
"""An internal function used to update (mutate in place) the loc_info. |
||||
|
||||
Args: |
||||
loc_info: LoCInfo to be updated |
||||
lines: list(str) representing the lines of a contract. |
||||
""" |
||||
cloc, sloc, loc = count_lines(lines) |
||||
loc_info.loc += loc |
||||
loc_info.cloc += cloc |
||||
loc_info.sloc += sloc |
||||
|
||||
|
||||
def compute_loc_metrics(slither: Slither) -> LoC: |
||||
"""Used to compute the lines of code metrics for a Slither object. |
||||
|
||||
Args: |
||||
slither: A Slither object |
||||
Returns: |
||||
A LoC object |
||||
""" |
||||
|
||||
loc = LoC() |
||||
|
||||
for filename, source_code in slither.source_code.items(): |
||||
current_lines = source_code.splitlines() |
||||
is_dep = False |
||||
if slither.crytic_compile: |
||||
is_dep = slither.crytic_compile.is_dependency(filename) |
||||
loc_type = loc.dep if is_dep else loc.test if is_test_file(Path(filename)) else loc.src |
||||
_update_lines(loc_type, current_lines) |
||||
return loc |
@ -1,12 +1,14 @@ |
||||
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 |
||||
|
||||
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.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.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.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.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.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 |
||||
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 |
||||
|
||||
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 |
||||
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 |
||||
|
||||
E.f() (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#57-61) passes array E.x (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#54) by reference to E.setByValue(uint256[1],uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.4.25/array_by_reference.sol#63-66) which only takes arrays by value |
||||
|
||||
|
@ -1,12 +1,14 @@ |
||||
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 |
||||
|
||||
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.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.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.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.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.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 |
||||
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 |
||||
|
||||
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 |
||||
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 |
||||
|
||||
E.f() (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#57-61) passes array E.x (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#54) by reference to E.setByValue(uint256[1],uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.5.16/array_by_reference.sol#63-66) which only takes arrays by value |
||||
|
||||
|
@ -1,12 +1,14 @@ |
||||
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 |
||||
|
||||
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.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.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.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.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.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 |
||||
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 |
||||
|
||||
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 |
||||
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 |
||||
|
||||
E.f() (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#57-61) passes array E.x (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#54) by reference to E.setByValue(uint256[1],uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.6.11/array_by_reference.sol#63-66) which only takes arrays by value |
||||
|
||||
|
@ -1,12 +1,14 @@ |
||||
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 |
||||
|
||||
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.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.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.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.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.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 |
||||
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 |
||||
|
||||
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 |
||||
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 |
||||
|
||||
E.f() (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#57-61) passes array E.x (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#54) by reference to E.setByValue(uint256[1],uint256[1]) (tests/e2e/detectors/test_data/array-by-reference/0.7.6/array_by_reference.sol#63-66) which only takes arrays by value |
||||
|
||||
|
@ -0,0 +1,18 @@ |
||||
Loop condition at i < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#36) should use cached array length instead of referencing `length` member of the storage array. |
||||
|
||||
Loop condition at i_scope_22 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#166) should use cached array length instead of referencing `length` member of the storage array. |
||||
|
||||
Loop condition at j_scope_11 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#108) should use cached array length instead of referencing `length` member of the storage array. |
||||
|
||||
Loop condition at i_scope_6 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#79) should use cached array length instead of referencing `length` member of the storage array. |
||||
|
||||
Loop condition at i_scope_21 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#160) should use cached array length instead of referencing `length` member of the storage array. |
||||
|
||||
Loop condition at k_scope_9 < array2.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#98) should use cached array length instead of referencing `length` member of the storage array. |
||||
|
||||
Loop condition at k_scope_17 < array2.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#132) should use cached array length instead of referencing `length` member of the storage array. |
||||
|
||||
Loop condition at j_scope_15 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#125) should use cached array length instead of referencing `length` member of the storage array. |
||||
|
||||
Loop condition at i_scope_4 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#67) should use cached array length instead of referencing `length` member of the storage array. |
||||
|
@ -1,8 +1,8 @@ |
||||
ERC20 event IERC20BadTransfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.4.25/erc20_indexed.sol#19)does not index parameter to |
||||
ERC20 event IERC20Bad.Approval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.4.25/erc20_indexed.sol#20)does not index parameter owner |
||||
|
||||
ERC20 event IERC20BadApproval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.4.25/erc20_indexed.sol#20)does not index parameter owner |
||||
ERC20 event IERC20Bad.Transfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.4.25/erc20_indexed.sol#19)does not index parameter from |
||||
|
||||
ERC20 event IERC20BadTransfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.4.25/erc20_indexed.sol#19)does not index parameter from |
||||
ERC20 event IERC20Bad.Approval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.4.25/erc20_indexed.sol#20)does not index parameter spender |
||||
|
||||
ERC20 event IERC20BadApproval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.4.25/erc20_indexed.sol#20)does not index parameter spender |
||||
ERC20 event IERC20Bad.Transfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.4.25/erc20_indexed.sol#19)does not index parameter to |
||||
|
||||
|
@ -1,8 +1,8 @@ |
||||
ERC20 event IERC20BadTransfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.5.16/erc20_indexed.sol#19)does not index parameter to |
||||
ERC20 event IERC20Bad.Approval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.5.16/erc20_indexed.sol#20)does not index parameter owner |
||||
|
||||
ERC20 event IERC20BadApproval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.5.16/erc20_indexed.sol#20)does not index parameter owner |
||||
ERC20 event IERC20Bad.Transfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.5.16/erc20_indexed.sol#19)does not index parameter from |
||||
|
||||
ERC20 event IERC20BadTransfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.5.16/erc20_indexed.sol#19)does not index parameter from |
||||
ERC20 event IERC20Bad.Approval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.5.16/erc20_indexed.sol#20)does not index parameter spender |
||||
|
||||
ERC20 event IERC20BadApproval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.5.16/erc20_indexed.sol#20)does not index parameter spender |
||||
ERC20 event IERC20Bad.Transfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.5.16/erc20_indexed.sol#19)does not index parameter to |
||||
|
||||
|
@ -1,8 +1,8 @@ |
||||
ERC20 event IERC20BadTransfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.6.11/erc20_indexed.sol#19)does not index parameter to |
||||
ERC20 event IERC20Bad.Approval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.6.11/erc20_indexed.sol#20)does not index parameter owner |
||||
|
||||
ERC20 event IERC20BadApproval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.6.11/erc20_indexed.sol#20)does not index parameter owner |
||||
ERC20 event IERC20Bad.Transfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.6.11/erc20_indexed.sol#19)does not index parameter from |
||||
|
||||
ERC20 event IERC20BadTransfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.6.11/erc20_indexed.sol#19)does not index parameter from |
||||
ERC20 event IERC20Bad.Approval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.6.11/erc20_indexed.sol#20)does not index parameter spender |
||||
|
||||
ERC20 event IERC20BadApproval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.6.11/erc20_indexed.sol#20)does not index parameter spender |
||||
ERC20 event IERC20Bad.Transfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.6.11/erc20_indexed.sol#19)does not index parameter to |
||||
|
||||
|
@ -1,8 +1,8 @@ |
||||
ERC20 event IERC20BadTransfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.7.6/erc20_indexed.sol#19)does not index parameter to |
||||
ERC20 event IERC20Bad.Approval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.7.6/erc20_indexed.sol#20)does not index parameter owner |
||||
|
||||
ERC20 event IERC20BadApproval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.7.6/erc20_indexed.sol#20)does not index parameter owner |
||||
ERC20 event IERC20Bad.Transfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.7.6/erc20_indexed.sol#19)does not index parameter from |
||||
|
||||
ERC20 event IERC20BadTransfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.7.6/erc20_indexed.sol#19)does not index parameter from |
||||
ERC20 event IERC20Bad.Approval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.7.6/erc20_indexed.sol#20)does not index parameter spender |
||||
|
||||
ERC20 event IERC20BadApproval(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.7.6/erc20_indexed.sol#20)does not index parameter spender |
||||
ERC20 event IERC20Bad.Transfer(address,address,uint256) (tests/e2e/detectors/test_data/erc20-indexed/0.7.6/erc20_indexed.sol#19)does not index parameter to |
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,171 @@ |
||||
pragma solidity 0.8.17; |
||||
|
||||
contract CacheArrayLength |
||||
{ |
||||
struct S |
||||
{ |
||||
uint s; |
||||
} |
||||
|
||||
S[] array; |
||||
S[] array2; |
||||
|
||||
function h() external |
||||
{ |
||||
|
||||
} |
||||
|
||||
function g() internal |
||||
{ |
||||
this.h(); |
||||
} |
||||
|
||||
function h_view() external view |
||||
{ |
||||
|
||||
} |
||||
|
||||
function g_view() internal view |
||||
{ |
||||
this.h_view(); |
||||
} |
||||
|
||||
function f() public |
||||
{ |
||||
// array accessed but length doesn't change |
||||
for (uint i = 0; i < array.length; i++) // warning should appear |
||||
{ |
||||
array[i] = S(0); |
||||
} |
||||
|
||||
// array.length doesn't change, but array.length not used in loop condition |
||||
for (uint i = array.length; i >= 0; i--) |
||||
{ |
||||
|
||||
} |
||||
|
||||
// array.length changes in the inner loop |
||||
for (uint i = 0; i < array.length; i++) |
||||
{ |
||||
for (uint j = i; j < 2 * i; j++) |
||||
array.push(S(j)); |
||||
} |
||||
|
||||
// array.length changes |
||||
for (uint i = 0; i < array.length; i++) |
||||
{ |
||||
array.pop(); |
||||
} |
||||
|
||||
// array.length changes |
||||
for (uint i = 0; i < array.length; i++) |
||||
{ |
||||
delete array; |
||||
} |
||||
|
||||
// array.length doesn't change despite using delete |
||||
for (uint i = 0; i < array.length; i++) // warning should appear |
||||
{ |
||||
delete array[i]; |
||||
} |
||||
|
||||
// array.length changes; push used in more complex expression |
||||
for (uint i = 0; i < array.length; i++) |
||||
{ |
||||
array.push() = S(i); |
||||
} |
||||
|
||||
// array.length doesn't change |
||||
for (uint i = 0; i < array.length; i++) // warning should appear |
||||
{ |
||||
array2.pop(); |
||||
array2.push(); |
||||
array2.push(S(i)); |
||||
delete array2; |
||||
delete array[0]; |
||||
} |
||||
|
||||
// array.length changes; array2.length doesn't change |
||||
for (uint i = 0; i < 7; i++) |
||||
{ |
||||
for (uint j = i; j < array.length; j++) |
||||
{ |
||||
for (uint k = 0; k < j; k++) |
||||
{ |
||||
|
||||
} |
||||
|
||||
for (uint k = 0; k < array2.length; k++) // warning should appear |
||||
{ |
||||
array.pop(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// array.length doesn't change; array2.length changes |
||||
for (uint i = 0; i < 7; i++) |
||||
{ |
||||
for (uint j = i; j < array.length; j++) // warning should appear |
||||
{ |
||||
for (uint k = 0; k < j; k++) |
||||
{ |
||||
|
||||
} |
||||
|
||||
for (uint k = 0; k < array2.length; k++) |
||||
{ |
||||
array2.pop(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// none of array.length and array2.length changes |
||||
for (uint i = 0; i < 7; i++) |
||||
{ |
||||
for (uint j = i; j < array.length; j++) // warning should appear |
||||
{ |
||||
for (uint k = 0; k < j; k++) |
||||
{ |
||||
|
||||
} |
||||
|
||||
for (uint k = 0; k < array2.length; k++) // warning should appear |
||||
{ |
||||
|
||||
} |
||||
} |
||||
} |
||||
|
||||
S[] memory array3; |
||||
|
||||
// array3 not modified, but it's not a storage array |
||||
for (uint i = 0; i < array3.length; i++) |
||||
{ |
||||
|
||||
} |
||||
|
||||
// array not modified, but it may potentially change in an internal function call |
||||
for (uint i = 0; i < array.length; i++) |
||||
{ |
||||
g(); |
||||
} |
||||
|
||||
// array not modified, but it may potentially change in an external function call |
||||
for (uint i = 0; i < array.length; i++) |
||||
{ |
||||
this.h(); |
||||
} |
||||
|
||||
// array not modified and it cannot be changed in a function call since g_view is a view function |
||||
for (uint i = 0; i < array.length; i++) // warning should appear |
||||
{ |
||||
g_view(); |
||||
} |
||||
|
||||
// array not modified and it cannot be changed in a function call since h_view is a view function |
||||
for (uint i = 0; i < array.length; i++) // warning should appear |
||||
{ |
||||
this.h_view(); |
||||
} |
||||
} |
||||
} |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,13 @@ |
||||
{ |
||||
"Lib": { |
||||
"f(Int)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" |
||||
}, |
||||
"T": { |
||||
"add_function_call(Int,Int)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: RETURN 2\n\"];\n}\n", |
||||
"add_op(Int,Int)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", |
||||
"lib_call(Int)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", |
||||
"neg_usertype(Int)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: RETURN 2\n\"];\n}\n", |
||||
"neg_int(int256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", |
||||
"eq_op(Int,Int)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
pragma solidity ^0.8.19; |
||||
|
||||
type Int is int; |
||||
using {add as +, eq as ==, add, neg as -, Lib.f} for Int global; |
||||
|
||||
function add(Int a, Int b) pure returns (Int) { |
||||
return Int.wrap(Int.unwrap(a) + Int.unwrap(b)); |
||||
} |
||||
|
||||
function eq(Int a, Int b) pure returns (bool) { |
||||
return true; |
||||
} |
||||
|
||||
function neg(Int a) pure returns (Int) { |
||||
return a; |
||||
} |
||||
|
||||
library Lib { |
||||
function f(Int r) internal {} |
||||
} |
||||
|
||||
contract T { |
||||
function add_function_call(Int b, Int c) public returns(Int) { |
||||
Int res = add(b,c); |
||||
return res; |
||||
} |
||||
|
||||
function add_op(Int b, Int c) public returns(Int) { |
||||
return b + c; |
||||
} |
||||
|
||||
function lib_call(Int b) public { |
||||
return b.f(); |
||||
} |
||||
|
||||
function neg_usertype(Int b) public returns(Int) { |
||||
Int res = -b; |
||||
return res; |
||||
} |
||||
|
||||
function neg_int(int b) public returns(int) { |
||||
return -b; |
||||
} |
||||
|
||||
function eq_op(Int b, Int c) public returns(bool) { |
||||
return b == c; |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue