Skip to content

Commit 9533947

Browse files
committed
Merge branch 'dev' into dev-multiple-compilation-units
2 parents 6233f31 + 4a8cdf7 commit 9533947

File tree

6,220 files changed

+155563
-23835
lines changed

Some content is hidden

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

6,220 files changed

+155563
-23835
lines changed

.github/workflows/parser.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@ jobs:
3535
3636
git clone https://github.com/crytic/solc-select.git
3737
cd solc-select
38-
git checkout 857d6fa883d9283454be1cb2d869a8f9962b27b8
38+
git checkout 119dd05f58341811cb02b546f25269a7e8a10875
39+
python setup.py install
40+
solc-select install all
41+
solc-select use 0.8.0
3942
cd ..
40-
./solc-select/scripts/install.sh
41-
export PATH=/home/runner/.solc-select:$PATH
42-
echo "export PATH=/home/runner/.solc-select:$PATH" >> ~/.bashrc
43-
solc use 0.7.3
4443
4544
- name: Test with pytest
4645
run: |

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ To see the tests coverage, run `pytest tests/test_detectors.py --cov=slither/d
5151

5252
### Parser tests
5353
- Create a test in `tests/ast-parsing`
54+
- Run `python ./tests/test_ast_parsing.py --compile`. This will compile the artifact in `tests/compile`. Add the compiled artifact to git.
5455
- Run `python ./tests/test_ast_parsing.py --generate`. This will generate the json artifacts in `tests/expected_json`. Add the generated files to git.
5556
- Run `pytest ./tests/test_ast_parsing.py` and check that everything worked.
5657

slither/core/compilation_unit.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit
5454

5555
self._source_units: Dict[int, str] = {}
5656

57+
self.counter_slithir_tuple = 0
58+
self.counter_slithir_temporary = 0
59+
self.counter_slithir_reference = 0
60+
5761
@property
5862
def core(self) -> "SlitherCore":
5963
return self._core

slither/core/declarations/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@
1313
from .structure import Structure
1414
from .enum_contract import EnumContract
1515
from .structure_contract import StructureContract
16+
from .function_contract import FunctionContract

slither/core/declarations/contract.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@
2424
# pylint: disable=too-many-lines,too-many-instance-attributes,import-outside-toplevel,too-many-nested-blocks
2525
if TYPE_CHECKING:
2626
from slither.utils.type_helpers import LibraryCallType, HighLevelCallType, InternalCallType
27-
from slither.core.declarations import Enum, Event, Modifier, EnumContract, StructureContract
27+
from slither.core.declarations import (
28+
Enum,
29+
Event,
30+
Modifier,
31+
EnumContract,
32+
StructureContract,
33+
FunctionContract,
34+
)
2835
from slither.slithir.variables.variable import SlithIRVariable
2936
from slither.core.variables.variable import Variable
3037
from slither.core.variables.state_variable import StateVariable
@@ -57,7 +64,7 @@ def __init__(self, compilation_unit: "SlitherCompilationUnit"):
5764
self._variables: Dict[str, "StateVariable"] = {}
5865
self._variables_ordered: List["StateVariable"] = []
5966
self._modifiers: Dict[str, "Modifier"] = {}
60-
self._functions: Dict[str, "Function"] = {}
67+
self._functions: Dict[str, "FunctionContract"] = {}
6168
self._linearizedBaseContracts = List[int]
6269

6370
# The only str is "*"
@@ -390,23 +397,23 @@ def functions_signatures_declared(self) -> List[str]:
390397
return self._signatures_declared
391398

392399
@property
393-
def functions(self) -> List["Function"]:
400+
def functions(self) -> List["FunctionContract"]:
394401
"""
395402
list(Function): List of the functions
396403
"""
397404
return list(self._functions.values())
398405

399-
def available_functions_as_dict(self) -> Dict[str, "Function"]:
406+
def available_functions_as_dict(self) -> Dict[str, "FunctionContract"]:
400407
if self._available_functions_as_dict is None:
401408
self._available_functions_as_dict = {
402409
f.full_name: f for f in self._functions.values() if not f.is_shadowed
403410
}
404411
return self._available_functions_as_dict
405412

406-
def add_function(self, func: "Function"):
413+
def add_function(self, func: "FunctionContract"):
407414
self._functions[func.canonical_name] = func
408415

409-
def set_functions(self, functions: Dict[str, "Function"]):
416+
def set_functions(self, functions: Dict[str, "FunctionContract"]):
410417
"""
411418
Set the functions
412419
@@ -416,21 +423,21 @@ def set_functions(self, functions: Dict[str, "Function"]):
416423
self._functions = functions
417424

418425
@property
419-
def functions_inherited(self) -> List["Function"]:
426+
def functions_inherited(self) -> List["FunctionContract"]:
420427
"""
421428
list(Function): List of the inherited functions
422429
"""
423430
return [f for f in self.functions if f.contract_declarer != self]
424431

425432
@property
426-
def functions_declared(self) -> List["Function"]:
433+
def functions_declared(self) -> List["FunctionContract"]:
427434
"""
428435
list(Function): List of the functions defined within the contract (not inherited)
429436
"""
430437
return [f for f in self.functions if f.contract_declarer == self]
431438

432439
@property
433-
def functions_entry_points(self) -> List["Function"]:
440+
def functions_entry_points(self) -> List["FunctionContract"]:
434441
"""
435442
list(Functions): List of public and external functions
436443
"""

slither/core/solidity_types/elementary_type.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,6 @@
8585
Max_Uint = {k: 2 ** (8 * i) - 1 if i > 0 else 2 ** 256 - 1 for i, k in enumerate(Uint)}
8686
Min_Uint = {k: 0 for k in Uint}
8787

88-
MaxValues = dict(Max_Int, **Max_Uint)
89-
MinValues = dict(Min_Int, **Min_Uint)
9088

9189
Byte = [
9290
"byte",
@@ -125,6 +123,16 @@
125123
"bytes32",
126124
]
127125

126+
Max_Byte = {k: 2 ** (8 * (i + 1)) - 1 for i, k in enumerate(Byte[2:])}
127+
Max_Byte["bytes"] = None
128+
Max_Byte["byte"] = 255
129+
Min_Byte = {k: 1 << (4 + 8 * i) for i, k in enumerate(Byte[2:])}
130+
Min_Byte["bytes"] = 0x0
131+
Min_Byte["byte"] = 0x10
132+
133+
MaxValues = dict(dict(Max_Int, **Max_Uint), **Max_Byte)
134+
MinValues = dict(dict(Min_Int, **Min_Uint), **Min_Byte)
135+
128136
# https://solidity.readthedocs.io/en/v0.4.24/types.html#fixed-point-numbers
129137
M = list(range(8, 257, 8))
130138
N = list(range(0, 81))

slither/detectors/all_detectors.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from .statements.assembly import Assembly
2222
from .operations.low_level_calls import LowLevelCalls
2323
from .operations.unused_return_values import UnusedReturnValues
24+
from .operations.unchecked_transfer import UncheckedTransfer
2425
from .naming_convention.naming_convention import NamingConvention
2526
from .functions.external_function import ExternalFunction
2627
from .statements.controlled_delegatecall import ControlledDelegateCall

slither/detectors/operations/unchecked_low_level_return_values.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,5 @@ class UncheckedLowLevel(UnusedReturnValues):
3434

3535
WIKI_RECOMMENDATION = "Ensure that the return value of a low-level call is checked or logged."
3636

37-
_txt_description = "low-level calls"
38-
3937
def _is_instance(self, ir): # pylint: disable=no-self-use
4038
return isinstance(ir, LowLevelCall)

slither/detectors/operations/unchecked_send_return_value.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,5 @@ class UncheckedSend(UnusedReturnValues):
3535

3636
WIKI_RECOMMENDATION = "Ensure that the return value of `send` is checked or logged."
3737

38-
_txt_description = "send calls"
39-
4038
def _is_instance(self, ir): # pylint: disable=no-self-use
4139
return isinstance(ir, Send)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""
2+
Module detecting unused transfer/transferFrom return values from external calls
3+
"""
4+
5+
from slither.core.declarations import Function
6+
from slither.detectors.abstract_detector import DetectorClassification
7+
from slither.detectors.operations.unused_return_values import UnusedReturnValues
8+
from slither.slithir.operations import HighLevelCall
9+
10+
11+
class UncheckedTransfer(UnusedReturnValues):
12+
"""
13+
If the return value of a transfer/transferFrom function is never used, it's likely to be bug
14+
"""
15+
16+
ARGUMENT = "unchecked-transfer"
17+
HELP = "Unchecked tokens transfer"
18+
IMPACT = DetectorClassification.HIGH
19+
CONFIDENCE = DetectorClassification.MEDIUM
20+
21+
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-transfer"
22+
23+
WIKI_TITLE = "Unchecked transfer"
24+
WIKI_DESCRIPTION = "The return value of an external transfer/transferFrom call is not checked"
25+
WIKI_EXPLOIT_SCENARIO = """
26+
```solidity
27+
contract Token {
28+
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
29+
}
30+
contract MyBank{
31+
mapping(address => uint) balances;
32+
Token token;
33+
function deposit(uint amount) public{
34+
token.transferFrom(msg.sender, address(this), amount);
35+
balances[msg.sender] += amount;
36+
}
37+
}
38+
```
39+
Several tokens do not revert in case of failure and return false. If one of these tokens is used in `MyBank`, `deposit` will not revert if the transfer fails, and an attacker can call `deposit` for free.."""
40+
41+
WIKI_RECOMMENDATION = (
42+
"Use `SafeERC20`, or ensure that the transfer/transferFrom return value is checked."
43+
)
44+
45+
def _is_instance(self, ir): # pylint: disable=no-self-use
46+
return (
47+
isinstance(ir, HighLevelCall)
48+
and isinstance(ir.function, Function)
49+
and ir.function.solidity_signature
50+
in ["transfer(address,uint256)", "transferFrom(address,address,uint256)"]
51+
)

0 commit comments

Comments
 (0)