Skip to content

Commit 73dc9f9

Browse files
authored
Merge pull request #2635 from crytic/dev
Sync Master <> Dev
2 parents 3befc96 + bc8e8f2 commit 73dc9f9

File tree

122 files changed

+2911
-736
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+2911
-736
lines changed

.github/workflows/black_auto.yml

+9-7
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ jobs:
3030
with:
3131
python-version: 3.8
3232

33-
- name: Install Python dependencies
34-
run: pip install .[dev]
33+
- name: Run black
34+
uses: psf/black@stable
35+
with:
36+
options: ""
37+
summary: false
38+
version: "~= 22.3.0"
3539

36-
- name: Run linters
37-
uses: wearerequired/lint-action@v2
40+
- name: Annotate diff changes using reviewdog
41+
uses: reviewdog/action-suggester@v1
3842
with:
39-
auto_fix: true
40-
black: true
41-
black_auto_fix: true
43+
tool_name: blackfmt

.github/workflows/ci.yml

+3-20
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,9 @@ jobs:
2525
strategy:
2626
fail-fast: false
2727
matrix:
28-
os: ["ubuntu-latest", "windows-2022"]
28+
os: ${{ (github.event_name == 'pull_request' && fromJSON('["ubuntu-latest"]')) || fromJSON('["ubuntu-latest", "windows-2022"]') }}
2929
python: ${{ (github.event_name == 'pull_request' && fromJSON('["3.8", "3.12"]')) || fromJSON('["3.8", "3.9", "3.10", "3.11", "3.12"]') }}
30-
type: ["cli",
31-
"dapp",
32-
"data_dependency",
33-
"path_filtering",
34-
# "embark",
35-
"erc",
36-
# "etherlime",
37-
"etherscan",
38-
"find_paths",
39-
"flat",
40-
"interface",
41-
"kspec",
42-
"printers",
43-
# "prop"
44-
"simil",
45-
"slither_config",
46-
"truffle",
47-
"upgradability"]
30+
type: ${{ (github.event_name == 'pull_request' && fromJSON('["data_dependency", "path_filtering","erc","find_paths","flat","interface", "printers","slither_config","upgradability"]')) || fromJSON('["data_dependency", "path_filtering","erc","find_paths","flat","interface", "printers","slither_config","upgradability", "cli", "dapp", "etherscan", "kspec", "simil", "truffle"]') }}
4831
exclude:
4932
# Requires nix
5033
- os: windows-2022
@@ -67,7 +50,7 @@ jobs:
6750
6851
- name: Set up nix
6952
if: matrix.type == 'dapp'
70-
uses: cachix/install-nix-action@V27
53+
uses: cachix/install-nix-action@v30
7154

7255
- name: Set up cachix
7356
if: matrix.type == 'dapp'

.github/workflows/publish.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
path: dist/
4545

4646
- name: publish
47-
uses: pypa/gh-action-pypi-publish@v1.9.0
47+
uses: pypa/gh-action-pypi-publish@v1.12.3
4848

4949
- name: sign
5050
uses: sigstore/[email protected]

CODEOWNERS

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
* @montyly @0xalpharush @smonicas
2-
/slither/tools/read_storage/ @0xalpharush
1+
* @montyly @smonicas
32
/slither/tools/doctor/ @elopez
43
/slither/slithir/ @montyly
54
/slither/analyses/ @montyly

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ TEST_MODULE := tests
66
ALL_PY_SRCS := $(shell find $(PY_MODULE) -name '*.py') \
77
$(shell find test -name '*.py')
88

9-
# Optionally overriden by the user, if they're using a virtual environment manager.
9+
# Optionally overridden by the user, if they're using a virtual environment manager.
1010
VENV ?= env
1111

1212
# On Windows, venv scripts/shims are under `Scripts` instead of `bin`.

README.md

+84-72
Large diffs are not rendered by default.

scripts/ci_test_printers.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
cd tests/e2e/solc_parsing/test_data/compile/ || exit
66

77
# Do not test the evm printer,as it needs a refactoring
8-
ALL_PRINTERS="cfg,constructor-calls,contract-summary,data-dependency,echidna,function-id,function-summary,modifiers,call-graph,halstead,human-summary,inheritance,inheritance-graph,loc,martin,slithir,slithir-ssa,vars-and-auth,require,variable-order,declaration,ck"
8+
ALL_PRINTERS="cfg,constructor-calls,contract-summary,data-dependency,echidna,function-id,function-summary,modifiers,call-graph,halstead,human-summary,inheritance,inheritance-graph,loc,martin,slithir,slithir-ssa,vars-and-auth,require,variable-order,declaration,ck,cheatcode"
99

1010
# Only test 0.5.17 to limit test time
1111
for file in *0.5.17-compact.zip; do

setup.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
description="Slither is a Solidity and Vyper static analysis framework written in Python 3.",
99
url="https://github.com/crytic/slither",
1010
author="Trail of Bits",
11-
version="0.10.4",
11+
version="0.11.0",
1212
packages=find_packages(),
1313
python_requires=">=3.8",
1414
install_requires=[
1515
"packaging",
1616
"prettytable>=3.10.2",
1717
"pycryptodome>=3.4.6",
18-
"crytic-compile>=0.3.7,<0.4.0",
18+
"crytic-compile>=0.3.8,<0.4.0",
1919
# "crytic-compile@git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile",
2020
"web3>=6.20.2, <7",
2121
"eth-abi>=4.0.0",

slither/analyses/write/are_variables_written.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def _visit(
8686
lvalue = refs_lvalues
8787

8888
ret: List[Variable] = []
89-
if not node.sons and node.type not in [NodeType.THROW, NodeType.RETURN]:
89+
if not node.sons and node.type is not NodeType.THROW:
9090
ret += [v for v in variables_to_write if v not in variables_written]
9191

9292
# Explore sons if

slither/core/cfg/node.py

+30-40
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,6 @@
4646
if TYPE_CHECKING:
4747
from slither.slithir.variables.variable import SlithIRVariable
4848
from slither.core.compilation_unit import SlitherCompilationUnit
49-
from slither.utils.type_helpers import (
50-
InternalCallType,
51-
HighLevelCallType,
52-
LibraryCallType,
53-
LowLevelCallType,
54-
)
5549
from slither.core.cfg.scope import Scope
5650
from slither.core.scope.scope import FileScope
5751

@@ -153,11 +147,11 @@ def __init__(
153147
self._ssa_vars_written: List["SlithIRVariable"] = []
154148
self._ssa_vars_read: List["SlithIRVariable"] = []
155149

156-
self._internal_calls: List[Union["Function", "SolidityFunction"]] = []
157-
self._solidity_calls: List[SolidityFunction] = []
158-
self._high_level_calls: List["HighLevelCallType"] = [] # contains library calls
159-
self._library_calls: List["LibraryCallType"] = []
160-
self._low_level_calls: List["LowLevelCallType"] = []
150+
self._internal_calls: List[InternalCall] = [] # contains solidity calls
151+
self._solidity_calls: List[SolidityCall] = []
152+
self._high_level_calls: List[Tuple[Contract, HighLevelCall]] = [] # contains library calls
153+
self._library_calls: List[LibraryCall] = []
154+
self._low_level_calls: List[LowLevelCall] = []
161155
self._external_calls_as_expressions: List[Expression] = []
162156
self._internal_calls_as_expressions: List[Expression] = []
163157
self._irs: List[Operation] = []
@@ -226,8 +220,9 @@ def type(self, new_type: NodeType) -> None:
226220
@property
227221
def will_return(self) -> bool:
228222
if not self.sons and self.type != NodeType.THROW:
229-
if SolidityFunction("revert()") not in self.solidity_calls:
230-
if SolidityFunction("revert(string)") not in self.solidity_calls:
223+
solidity_calls = [ir.function for ir in self.solidity_calls]
224+
if SolidityFunction("revert()") not in solidity_calls:
225+
if SolidityFunction("revert(string)") not in solidity_calls:
231226
return True
232227
return False
233228

@@ -373,44 +368,38 @@ def variables_written_as_expression(self, exprs: List[Expression]) -> None:
373368
###################################################################################
374369

375370
@property
376-
def internal_calls(self) -> List["InternalCallType"]:
371+
def internal_calls(self) -> List[InternalCall]:
377372
"""
378-
list(Function or SolidityFunction): List of internal/soldiity function calls
373+
list(InternalCall): List of IR operations with internal/solidity function calls
379374
"""
380375
return list(self._internal_calls)
381376

382377
@property
383-
def solidity_calls(self) -> List[SolidityFunction]:
378+
def solidity_calls(self) -> List[SolidityCall]:
384379
"""
385-
list(SolidityFunction): List of Soldity calls
380+
list(SolidityCall): List of IR operations with solidity calls
386381
"""
387382
return list(self._solidity_calls)
388383

389384
@property
390-
def high_level_calls(self) -> List["HighLevelCallType"]:
385+
def high_level_calls(self) -> List[HighLevelCall]:
391386
"""
392-
list((Contract, Function|Variable)):
393-
List of high level calls (external calls).
394-
A variable is called in case of call to a public state variable
387+
list(HighLevelCall): List of IR operations with high level calls (external calls).
395388
Include library calls
396389
"""
397390
return list(self._high_level_calls)
398391

399392
@property
400-
def library_calls(self) -> List["LibraryCallType"]:
393+
def library_calls(self) -> List[LibraryCall]:
401394
"""
402-
list((Contract, Function)):
403-
Include library calls
395+
list(LibraryCall): List of IR operations with library calls.
404396
"""
405397
return list(self._library_calls)
406398

407399
@property
408-
def low_level_calls(self) -> List["LowLevelCallType"]:
400+
def low_level_calls(self) -> List[LowLevelCall]:
409401
"""
410-
list((Variable|SolidityVariable, str)): List of low_level call
411-
A low level call is defined by
412-
- the variable called
413-
- the name of the function (call/delegatecall/codecall)
402+
list(LowLevelCall): List of IR operations with low_level call
414403
"""
415404
return list(self._low_level_calls)
416405

@@ -529,8 +518,9 @@ def contains_require_or_assert(self) -> bool:
529518
bool: True if the node has a require or assert call
530519
"""
531520
return any(
532-
c.name in ["require(bool)", "require(bool,string)", "assert(bool)"]
533-
for c in self.internal_calls
521+
ir.function.name
522+
in ["require(bool)", "require(bool,string)", "require(bool,error)", "assert(bool)"]
523+
for ir in self.internal_calls
534524
)
535525

536526
def contains_if(self, include_loop: bool = True) -> bool:
@@ -894,11 +884,11 @@ def _find_read_write_call(self) -> None: # pylint: disable=too-many-statements
894884
self._vars_written.append(var)
895885

896886
if isinstance(ir, InternalCall):
897-
self._internal_calls.append(ir.function)
887+
self._internal_calls.append(ir)
898888
if isinstance(ir, SolidityCall):
899889
# TODO: consider removing dependancy of solidity_call to internal_call
900-
self._solidity_calls.append(ir.function)
901-
self._internal_calls.append(ir.function)
890+
self._solidity_calls.append(ir)
891+
self._internal_calls.append(ir)
902892
if (
903893
isinstance(ir, SolidityCall)
904894
and ir.function == SolidityFunction("sstore(uint256,uint256)")
@@ -916,22 +906,22 @@ def _find_read_write_call(self) -> None: # pylint: disable=too-many-statements
916906
self._vars_read.append(ir.arguments[0])
917907
if isinstance(ir, LowLevelCall):
918908
assert isinstance(ir.destination, (Variable, SolidityVariable))
919-
self._low_level_calls.append((ir.destination, str(ir.function_name.value)))
909+
self._low_level_calls.append(ir)
920910
elif isinstance(ir, HighLevelCall) and not isinstance(ir, LibraryCall):
921911
# Todo investigate this if condition
922912
# It does seem right to compare against a contract
923913
# This might need a refactoring
924914
if isinstance(ir.destination.type, Contract):
925-
self._high_level_calls.append((ir.destination.type, ir.function))
915+
self._high_level_calls.append((ir.destination.type, ir))
926916
elif ir.destination == SolidityVariable("this"):
927917
func = self.function
928918
# Can't use this in a top level function
929919
assert isinstance(func, FunctionContract)
930-
self._high_level_calls.append((func.contract, ir.function))
920+
self._high_level_calls.append((func.contract, ir))
931921
else:
932922
try:
933923
# Todo this part needs more tests and documentation
934-
self._high_level_calls.append((ir.destination.type.type, ir.function))
924+
self._high_level_calls.append((ir.destination.type.type, ir))
935925
except AttributeError as error:
936926
# pylint: disable=raise-missing-from
937927
raise SlitherException(
@@ -940,8 +930,8 @@ def _find_read_write_call(self) -> None: # pylint: disable=too-many-statements
940930
elif isinstance(ir, LibraryCall):
941931
assert isinstance(ir.destination, Contract)
942932
assert isinstance(ir.function, Function)
943-
self._high_level_calls.append((ir.destination, ir.function))
944-
self._library_calls.append((ir.destination, ir.function))
933+
self._high_level_calls.append((ir.destination, ir))
934+
self._library_calls.append(ir)
945935

946936
self._vars_read = list(set(self._vars_read))
947937
self._state_vars_read = [v for v in self._vars_read if isinstance(v, StateVariable)]

slither/core/compilation_unit.py

+40-20
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit
7373
# Memoize
7474
self._all_state_variables: Optional[Set[StateVariable]] = None
7575

76-
self._storage_layouts: Dict[str, Dict[str, Tuple[int, int]]] = {}
76+
self._persistent_storage_layouts: Dict[str, Dict[str, Tuple[int, int]]] = {}
77+
self._transient_storage_layouts: Dict[str, Dict[str, Tuple[int, int]]] = {}
7778

7879
self._contract_with_missing_inheritance: Set[Contract] = set()
7980

@@ -297,33 +298,52 @@ def get_scope(self, filename_str: str) -> FileScope:
297298

298299
def compute_storage_layout(self) -> None:
299300
assert self.is_solidity
301+
300302
for contract in self.contracts_derived:
301-
self._storage_layouts[contract.name] = {}
302-
303-
slot = 0
304-
offset = 0
305-
for var in contract.stored_state_variables_ordered:
306-
assert var.type
307-
size, new_slot = var.type.storage_size
308-
309-
if new_slot:
310-
if offset > 0:
311-
slot += 1
312-
offset = 0
313-
elif size + offset > 32:
303+
self._compute_storage_layout(contract.name, contract.storage_variables_ordered, False)
304+
self._compute_storage_layout(contract.name, contract.transient_variables_ordered, True)
305+
306+
def _compute_storage_layout(
307+
self, contract_name: str, state_variables_ordered: List[StateVariable], is_transient: bool
308+
):
309+
if is_transient:
310+
self._transient_storage_layouts[contract_name] = {}
311+
else:
312+
self._persistent_storage_layouts[contract_name] = {}
313+
314+
slot = 0
315+
offset = 0
316+
for var in state_variables_ordered:
317+
assert var.type
318+
size, new_slot = var.type.storage_size
319+
320+
if new_slot:
321+
if offset > 0:
314322
slot += 1
315323
offset = 0
324+
elif size + offset > 32:
325+
slot += 1
326+
offset = 0
316327

317-
self._storage_layouts[contract.name][var.canonical_name] = (
328+
if is_transient:
329+
self._transient_storage_layouts[contract_name][var.canonical_name] = (
318330
slot,
319331
offset,
320332
)
321-
if new_slot:
322-
slot += math.ceil(size / 32)
323-
else:
324-
offset += size
333+
else:
334+
self._persistent_storage_layouts[contract_name][var.canonical_name] = (
335+
slot,
336+
offset,
337+
)
338+
339+
if new_slot:
340+
slot += math.ceil(size / 32)
341+
else:
342+
offset += size
325343

326344
def storage_layout_of(self, contract: Contract, var: StateVariable) -> Tuple[int, int]:
327-
return self._storage_layouts[contract.name][var.canonical_name]
345+
if var.is_stored:
346+
return self._persistent_storage_layouts[contract.name][var.canonical_name]
347+
return self._transient_storage_layouts[contract.name][var.canonical_name]
328348

329349
# endregion

0 commit comments

Comments
 (0)