Merge branch 'dev' into array-type

pull/1784/head
alpharush 1 year ago committed by GitHub
commit 05d801fe8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/workflows/black.yml
  2. 2
      .github/workflows/linter.yml
  3. 2
      .github/workflows/pip-audit.yml
  4. 2
      .github/workflows/pylint.yml
  5. 10
      examples/flat/a.sol
  6. 13
      examples/flat/b.sol
  7. 10
      scripts/ci_test_flat.sh
  8. 2
      setup.py
  9. 1
      slither/analyses/data_dependency/data_dependency.py
  10. 6
      slither/core/compilation_unit.py
  11. 7
      slither/core/declarations/custom_error.py
  12. 4
      slither/core/declarations/solidity_variables.py
  13. 1
      slither/detectors/all_detectors.py
  14. 4
      slither/detectors/assembly/shift_parameter_mixup.py
  15. 104
      slither/detectors/operations/encode_packed.py
  16. 42
      slither/detectors/operations/unused_return_values.py
  17. 31
      slither/detectors/reentrancy/reentrancy_events.py
  18. 23
      slither/detectors/statements/incorrect_strict_equality.py
  19. 9
      slither/slithir/convert.py
  20. 2
      slither/slithir/operations/assignment.py
  21. 1
      slither/slithir/operations/binary.py
  22. 3
      slither/slithir/operations/new_array.py
  23. 3
      slither/slithir/operations/new_contract.py
  24. 3
      slither/slithir/operations/new_structure.py
  25. 2
      slither/slithir/operations/unary.py
  26. 1
      slither/solc_parsing/declarations/function.py
  27. 3
      slither/solc_parsing/declarations/modifier.py
  28. 2
      slither/tools/flattening/export/export.py
  29. 45
      slither/tools/flattening/flattening.py
  30. 2
      slither/tools/read_storage/read_storage.py
  31. 181
      slither/utils/code_generation.py
  32. 6
      slither/utils/myprettytable.py
  33. 15
      slither/utils/type.py
  34. 1
      slither/visitors/slithir/expression_to_slithir.py
  35. 15
      tests/e2e/detectors/snapshots/detectors__detector_EncodePackedCollision_0_7_6_encode_packed_collision_sol__0.txt
  36. 2
      tests/e2e/detectors/snapshots/detectors__detector_ShiftParameterMixup_0_7_6_shift_parameter_mixup_sol__0.txt
  37. 8
      tests/e2e/detectors/snapshots/detectors__detector_UnusedReturnValues_0_4_25_unused_return_sol__0.txt
  38. 8
      tests/e2e/detectors/snapshots/detectors__detector_UnusedReturnValues_0_5_16_unused_return_sol__0.txt
  39. 8
      tests/e2e/detectors/snapshots/detectors__detector_UnusedReturnValues_0_6_11_unused_return_sol__0.txt
  40. 8
      tests/e2e/detectors/snapshots/detectors__detector_UnusedReturnValues_0_7_6_unused_return_sol__0.txt
  41. 78
      tests/e2e/detectors/test_data/encode-packed-collision/0.7.6/encode_packed_collision.sol
  42. BIN
      tests/e2e/detectors/test_data/encode-packed-collision/0.7.6/encode_packed_collision.sol-0.7.6.zip
  43. 24
      tests/e2e/detectors/test_data/incorrect-equality/0.7.6/incorrect_equality.sol
  44. BIN
      tests/e2e/detectors/test_data/incorrect-equality/0.7.6/incorrect_equality.sol-0.7.6.zip
  45. 3
      tests/e2e/detectors/test_data/incorrect-shift/0.7.6/shift_parameter_mixup.sol
  46. BIN
      tests/e2e/detectors/test_data/incorrect-shift/0.7.6/shift_parameter_mixup.sol-0.7.6.zip
  47. 8
      tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol
  48. BIN
      tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol-0.4.25.zip
  49. 8
      tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol
  50. BIN
      tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol-0.5.16.zip
  51. 8
      tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol
  52. BIN
      tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol-0.6.11.zip
  53. 8
      tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol
  54. BIN
      tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol-0.7.6.zip
  55. 5
      tests/e2e/detectors/test_detectors.py
  56. 1
      tests/e2e/solc_parsing/test_ast_parsing.py
  57. 9
      tests/e2e/solc_parsing/test_data/assembly-all.sol
  58. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.0-legacy.zip
  59. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.1-legacy.zip
  60. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.10-legacy.zip
  61. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.11-legacy.zip
  62. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.12-compact.zip
  63. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.12-legacy.zip
  64. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.13-compact.zip
  65. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.13-legacy.zip
  66. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.14-compact.zip
  67. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.14-legacy.zip
  68. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.15-compact.zip
  69. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.15-legacy.zip
  70. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.16-compact.zip
  71. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.16-legacy.zip
  72. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.17-compact.zip
  73. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.17-legacy.zip
  74. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.18-compact.zip
  75. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.18-legacy.zip
  76. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.19-compact.zip
  77. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.19-legacy.zip
  78. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.2-legacy.zip
  79. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.20-compact.zip
  80. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.20-legacy.zip
  81. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.21-compact.zip
  82. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.21-legacy.zip
  83. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.22-compact.zip
  84. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.22-legacy.zip
  85. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.23-compact.zip
  86. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.23-legacy.zip
  87. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.24-compact.zip
  88. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.24-legacy.zip
  89. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.25-compact.zip
  90. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.25-legacy.zip
  91. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.26-compact.zip
  92. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.26-legacy.zip
  93. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.3-legacy.zip
  94. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.4-legacy.zip
  95. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.5-legacy.zip
  96. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.6-legacy.zip
  97. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.7-legacy.zip
  98. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.8-legacy.zip
  99. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.4.9-legacy.zip
  100. BIN
      tests/e2e/solc_parsing/test_data/compile/assembly-all.sol-0.5.0-compact.zip
  101. Some files were not shown because too many files have changed in this diff Show More

@ -42,7 +42,7 @@ jobs:
cp pyproject.toml .github/linters
- name: Black
uses: github/super-linter/slim@v4.9.2
uses: super-linter/super-linter/slim@v4.9.2
if: always()
env:
# run linter on everything to catch preexisting problems

@ -43,7 +43,7 @@ jobs:
cp pyproject.toml .github/linters
- name: Lint everything else
uses: github/super-linter/slim@v4.9.2
uses: super-linter/super-linter/slim@v4.9.2
if: always()
env:
# run linter on everything to catch preexisting problems

@ -34,6 +34,6 @@ jobs:
python -m pip install .
- name: Run pip-audit
uses: trailofbits/gh-action-pip-audit@v0.0.4
uses: pypa/gh-action-pip-audit@v1.0.7
with:
virtual-environment: /tmp/pip-audit-env

@ -37,7 +37,7 @@ jobs:
cp pyproject.toml .github/linters
- name: Pylint
uses: github/super-linter/slim@v4.9.2
uses: super-linter/super-linter/slim@v4.9.2
if: always()
env:
# Run linters only on new files for pylint to speed up the CI

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

@ -1,6 +1,8 @@
#!/usr/bin/env bash
shopt -s extglob
### Test slither-prop
### Test slither-flat
solc-select use 0.8.19 --always-install
cd examples/flat || exit 1
@ -8,5 +10,11 @@ if ! slither-flat b.sol; then
echo "slither-flat failed"
exit 1
fi
SUFFIX="@(sol)"
if ! solc "crytic-export/flattening/"*$SUFFIX; then
echo "solc failed on flattened files"
exit 1
fi
exit 0

@ -13,7 +13,7 @@ setup(
python_requires=">=3.8",
install_requires=[
"packaging",
"prettytable>=0.7.2",
"prettytable>=3.3.0",
"pycryptodome>=3.4.6",
# "crytic-compile>=0.3.1,<0.4.0",
"crytic-compile@git+https://github.com/crytic/crytic-compile.git@windows-rel-path#egg=crytic-compile",

@ -129,6 +129,7 @@ GENERIC_TAINT = {
SolidityVariableComposed("msg.value"),
SolidityVariableComposed("msg.data"),
SolidityVariableComposed("tx.origin"),
SolidityVariableComposed("tx.gasprice"),
}

@ -13,7 +13,7 @@ from slither.core.declarations import (
Function,
Modifier,
)
from slither.core.declarations.custom_error import CustomError
from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel
from slither.core.declarations.enum_top_level import EnumTopLevel
from slither.core.declarations.function_top_level import FunctionTopLevel
from slither.core.declarations.structure_top_level import StructureTopLevel
@ -46,7 +46,7 @@ class SlitherCompilationUnit(Context):
self._using_for_top_level: List[UsingForTopLevel] = []
self._pragma_directives: List[Pragma] = []
self._import_directives: List[Import] = []
self._custom_errors: List[CustomError] = []
self._custom_errors: List[CustomErrorTopLevel] = []
self._user_defined_value_types: Dict[str, TypeAliasTopLevel] = {}
self._all_functions: Set[Function] = set()
@ -216,7 +216,7 @@ class SlitherCompilationUnit(Context):
return self._using_for_top_level
@property
def custom_errors(self) -> List[CustomError]:
def custom_errors(self) -> List[CustomErrorTopLevel]:
return self._custom_errors
@property

@ -1,8 +1,8 @@
from typing import List, TYPE_CHECKING, Optional, Type
from slither.core.solidity_types import UserDefinedType
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.variables.local_variable import LocalVariable
from slither.utils.type import is_underlying_type_address
if TYPE_CHECKING:
from slither.core.compilation_unit import SlitherCompilationUnit
@ -43,10 +43,7 @@ class CustomError(SourceMapping):
@staticmethod
def _convert_type_for_solidity_signature(t: Optional[Type]) -> str:
# pylint: disable=import-outside-toplevel
from slither.core.declarations import Contract
if isinstance(t, UserDefinedType) and isinstance(t.type, Contract):
if is_underlying_type_address(t):
return "address"
return str(t)

@ -201,6 +201,10 @@ class SolidityCustomRevert(SolidityFunction):
self._custom_error = custom_error
self._return_type: List[Union[TypeInformation, ElementaryType]] = []
@property
def custom_error(self) -> CustomError:
return self._custom_error
def __eq__(self, other: Any) -> bool:
return (
self.__class__ == other.__class__

@ -89,3 +89,4 @@ from .functions.protected_variable import ProtectedVariables
from .functions.permit_domain_signature_collision import DomainSeparatorCollision
from .functions.codex import Codex
from .functions.cyclomatic_complexity import CyclomaticComplexity
from .operations.encode_packed import EncodePackedCollision

@ -52,7 +52,9 @@ The shift statement will right-shift the constant 8 by `a` bits"""
BinaryType.LEFT_SHIFT,
BinaryType.RIGHT_SHIFT,
]:
if isinstance(ir.variable_left, Constant):
if isinstance(ir.variable_left, Constant) and not isinstance(
ir.variable_right, Constant
):
info: DETECTOR_INFO = [
f,
" contains an incorrect shift operation: ",

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

@ -3,7 +3,7 @@ Module detecting unused return values from external calls
"""
from typing import List
from slither.core.cfg.node import Node
from slither.core.cfg.node import Node, NodeType
from slither.core.declarations import Function
from slither.core.declarations.function_contract import FunctionContract
from slither.core.variables.state_variable import StateVariable
@ -12,8 +12,8 @@ from slither.detectors.abstract_detector import (
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import HighLevelCall
from slither.slithir.operations.operation import Operation
from slither.slithir.operations import HighLevelCall, Assignment, Unpack, Operation
from slither.slithir.variables import TupleVariable
from slither.utils.output import Output
@ -50,13 +50,18 @@ contract MyConc{
WIKI_RECOMMENDATION = "Ensure that all the return values of the function calls are used."
def _is_instance(self, ir: Operation) -> bool: # pylint: disable=no-self-use
return isinstance(ir, HighLevelCall) and (
(
isinstance(ir.function, Function)
and ir.function.solidity_signature
not in ["transfer(address,uint256)", "transferFrom(address,address,uint256)"]
return (
isinstance(ir, HighLevelCall)
and (
(
isinstance(ir.function, Function)
and ir.function.solidity_signature
not in ["transfer(address,uint256)", "transferFrom(address,address,uint256)"]
)
or not isinstance(ir.function, Function)
)
or not isinstance(ir.function, Function)
or ir.node.type == NodeType.TRY
and isinstance(ir, (Assignment, Unpack))
)
def detect_unused_return_values(
@ -71,18 +76,27 @@ contract MyConc{
"""
values_returned = []
nodes_origin = {}
# pylint: disable=too-many-nested-blocks
for n in f.nodes:
for ir in n.irs:
if self._is_instance(ir):
# if a return value is stored in a state variable, it's ok
if ir.lvalue and not isinstance(ir.lvalue, StateVariable):
values_returned.append(ir.lvalue)
values_returned.append((ir.lvalue, None))
nodes_origin[ir.lvalue] = ir
if isinstance(ir.lvalue, TupleVariable):
# we iterate the number of elements the tuple has
# and add a (variable, index) in values_returned for each of them
for index in range(len(ir.lvalue.type)):
values_returned.append((ir.lvalue, index))
for read in ir.read:
if read in values_returned:
values_returned.remove(read)
return [nodes_origin[value].node for value in values_returned]
remove = (read, ir.index) if isinstance(ir, Unpack) else (read, None)
if remove in values_returned:
# this is needed to remove the tuple variable when the first time one of its element is used
if remove[1] is not None and (remove[0], None) in values_returned:
values_returned.remove((remove[0], None))
values_returned.remove(remove)
return [nodes_origin[value].node for (value, _) in values_returned]
def _detect(self) -> List[Output]:
"""Detect high level calls which return a value that are never used"""

@ -29,24 +29,45 @@ class ReentrancyEvent(Reentrancy):
# region wiki_description
WIKI_DESCRIPTION = """
Detection of the [reentrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy).
Only report reentrancies leading to out-of-order events."""
Detects [reentrancies](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy) that allow manipulation of the order or value of events."""
# endregion wiki_description
# region wiki_exploit_scenario
WIKI_EXPLOIT_SCENARIO = """
```solidity
function bug(Called d){
contract ReentrantContract {
function f() external {
if (BugReentrancyEvents(msg.sender).counter() == 1) {
BugReentrancyEvents(msg.sender).count(this);
}
}
}
contract Counter {
uint public counter;
event Counter(uint);
}
contract BugReentrancyEvents is Counter {
function count(ReentrantContract d) external {
counter += 1;
d.f();
emit Counter(counter);
}
}
contract NoReentrancyEvents is Counter {
function count(ReentrantContract d) external {
counter += 1;
emit Counter(counter);
d.f();
}
}
```
If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, which might lead to issues for third parties."""
If the external call `d.f()` re-enters `BugReentrancyEvents`, the `Counter` events will be incorrect (`Counter(2)`, `Counter(2)`) whereas `NoReentrancyEvents` will correctly emit
(`Counter(1)`, `Counter(2)`). This may cause issues for offchain components that rely on the values of events e.g. checking for the amount deposited to a bridge."""
# endregion wiki_exploit_scenario
WIKI_RECOMMENDATION = "Apply the [`check-effects-interactions` pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)."
WIKI_RECOMMENDATION = "Apply the [`check-effects-interactions` pattern](https://docs.soliditylang.org/en/latest/security-considerations.html#re-entrancy)."
STANDARD_JSON = False

@ -31,6 +31,7 @@ from slither.slithir.variables.constant import Constant
from slither.slithir.variables.local_variable import LocalIRVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from slither.utils.output import Output
from slither.utils.type import is_underlying_type_address
class IncorrectStrictEquality(AbstractDetector):
@ -72,6 +73,19 @@ contract Crowdsale{
def is_direct_comparison(ir: Operation) -> bool:
return isinstance(ir, Binary) and ir.type == BinaryType.EQUAL
@staticmethod
def is_not_comparing_addresses(ir: Binary) -> bool:
"""
Comparing addresses strictly should not be flagged.
"""
if is_underlying_type_address(ir.variable_left.type) and is_underlying_type_address(
ir.variable_right.type
):
return False
return True
@staticmethod
def is_any_tainted(
variables: List[
@ -108,7 +122,6 @@ contract Crowdsale{
):
taints.append(ir.lvalue)
if isinstance(ir, HighLevelCall):
# print(ir.function.full_name)
if (
isinstance(ir.function, Function)
and ir.function.full_name == "balanceOf(address)"
@ -125,7 +138,6 @@ contract Crowdsale{
if isinstance(ir, Assignment):
if ir.rvalue in self.sources_taint:
taints.append(ir.lvalue)
return taints
# Retrieve all tainted (node, function) pairs
@ -145,7 +157,12 @@ contract Crowdsale{
for ir in node.irs_ssa:
# Filter to only tainted equality (==) comparisons
if self.is_direct_comparison(ir) and self.is_any_tainted(ir.used, taints, func):
if (
self.is_direct_comparison(ir)
# Filter out address comparisons which may occur due to lack of field sensitivity in data dependency
and self.is_not_comparing_addresses(ir)
and self.is_any_tainted(ir.used, taints, func)
):
if func not in results:
results[func] = []
results[func].append(node)

@ -1363,7 +1363,14 @@ def convert_to_pop(ir: HighLevelCall, node: "Node") -> List[Operation]:
# TODO the following is equivalent to length.points_to = arr
# Should it be removed?
ir_length.lvalue.points_to = arr
element_to_delete.set_type(ElementaryType("uint256"))
# Note bytes is an ElementaryType not ArrayType so in that case we use ir.destination.type
# while in other cases such as uint256[] (ArrayType) we use ir.destination.type.type
# in this way we will have the type always set to the corresponding ElementaryType
element_to_delete.set_type(
ir.destination.type
if isinstance(ir.destination.type, ElementaryType)
else ir.destination.type.type
)
ir_assign_element_to_delete.set_expression(ir.expression)
ir_assign_element_to_delete.set_node(ir.node)
ret.append(ir_assign_element_to_delete)

@ -50,5 +50,5 @@ class Assignment(OperationWithLValue):
points = lvalue.points_to
while isinstance(points, ReferenceVariable):
points = points.points_to
return f"{lvalue} (->{points}) := {self.rvalue}({self.rvalue.type})"
return f"{lvalue}({lvalue.type}) (->{points}) := {self.rvalue}({self.rvalue.type})"
return f"{lvalue}({lvalue.type}) := {self.rvalue}({self.rvalue.type})"

@ -94,7 +94,6 @@ class BinaryType(Enum):
return self in [
BinaryType.POWER,
BinaryType.MULTIPLICATION,
BinaryType.MODULO,
BinaryType.ADDITION,
BinaryType.SUBTRACTION,
BinaryType.DIVISION,

@ -32,4 +32,5 @@ class NewArray(Call, OperationWithLValue):
def __str__(self):
args = [str(a) for a in self.arguments]
return f"{self.lvalue} = new {self.array_type}({','.join(args)})"
lvalue = self.lvalue
return f"{lvalue}{lvalue.type}) = new {self.array_type}({','.join(args)})"

@ -104,4 +104,5 @@ class NewContract(Call, OperationWithLValue): # pylint: disable=too-many-instan
if self.call_salt:
options += f"salt:{self.call_salt} "
args = [str(a) for a in self.arguments]
return f"{self.lvalue} = new {self.contract_name}({','.join(args)}) {options}"
lvalue = self.lvalue
return f"{lvalue}({lvalue.type}) = new {self.contract_name}({','.join(args)}) {options}"

@ -39,4 +39,5 @@ class NewStructure(Call, OperationWithLValue):
def __str__(self):
args = [str(a) for a in self.arguments]
return f"{self.lvalue} = new {self.structure_name}({','.join(args)})"
lvalue = self.lvalue
return f"{lvalue}({lvalue.type}) = new {self.structure_name}({','.join(args)})"

@ -58,7 +58,7 @@ class Unary(OperationWithLValue):
@property
def type_str(self):
return self._type.value
return str(self._type)
def __str__(self):
return f"{self.lvalue} = {self.type_str} {self.rvalue} "

@ -774,6 +774,7 @@ class FunctionSolc(CallerContextExpression):
"nodeType": "Identifier",
"src": v["src"],
"name": v["name"],
"referencedDeclaration": v["id"],
"typeDescriptions": {"typeString": v["typeDescriptions"]["typeString"]},
}
var_identifiers.append(identifier)

@ -87,6 +87,9 @@ class ModifierSolc(FunctionSolc):
for node in self._node_to_nodesolc.values():
node.analyze_expressions(self)
for yul_parser in self._node_to_yulobject.values():
yul_parser.analyze_expressions()
self._rewrite_ternary_as_if_else()
self._remove_alone_endif()

@ -15,7 +15,7 @@ ZIP_TYPES_ACCEPTED = {
Export = namedtuple("Export", ["filename", "content"])
logger = logging.getLogger("Slither")
logger = logging.getLogger("Slither-flat")
def save_to_zip(files: List[Export], zip_filename: str, zip_type: str = "lzma"):

@ -11,6 +11,7 @@ from slither.core.declarations import SolidityFunction, EnumContract, StructureC
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_top_level import FunctionTopLevel
from slither.core.declarations.top_level import TopLevel
from slither.core.declarations.solidity_variables import SolidityCustomRevert
from slither.core.solidity_types import MappingType, ArrayType
from slither.core.solidity_types.type import Type
from slither.core.solidity_types.user_defined_type import UserDefinedType
@ -23,7 +24,8 @@ from slither.tools.flattening.export.export import (
save_to_disk,
)
logger = logging.getLogger("Slither-flattening")
logger = logging.getLogger("Slither-flat")
logger.setLevel(logging.INFO)
# index: where to start
# patch_type:
@ -75,6 +77,7 @@ class Flattening:
self._get_source_code_top_level(compilation_unit.structures_top_level)
self._get_source_code_top_level(compilation_unit.enums_top_level)
self._get_source_code_top_level(compilation_unit.custom_errors)
self._get_source_code_top_level(compilation_unit.variables_top_level)
self._get_source_code_top_level(compilation_unit.functions_top_level)
@ -249,12 +252,14 @@ class Flattening:
t: Type,
contract: Contract,
exported: Set[str],
list_contract: List[Contract],
list_top_level: List[TopLevel],
list_contract: Set[Contract],
list_top_level: Set[TopLevel],
):
if isinstance(t, UserDefinedType):
t_type = t.type
if isinstance(t_type, (EnumContract, StructureContract)):
if isinstance(t_type, TopLevel):
list_top_level.add(t_type)
elif isinstance(t_type, (EnumContract, StructureContract)):
if t_type.contract != contract and t_type.contract not in exported:
self._export_list_used_contracts(
t_type.contract, exported, list_contract, list_top_level
@ -275,8 +280,8 @@ class Flattening:
self,
contract: Contract,
exported: Set[str],
list_contract: List[Contract],
list_top_level: List[TopLevel],
list_contract: Set[Contract],
list_top_level: Set[TopLevel],
):
# TODO: investigate why this happen
if not isinstance(contract, Contract):
@ -332,19 +337,21 @@ class Flattening:
for read in ir.read:
if isinstance(read, TopLevel):
if read not in list_top_level:
list_top_level.append(read)
if isinstance(ir, InternalCall):
function_called = ir.function
if isinstance(function_called, FunctionTopLevel):
list_top_level.append(function_called)
if contract not in list_contract:
list_contract.append(contract)
list_top_level.add(read)
if isinstance(ir, InternalCall) and isinstance(ir.function, FunctionTopLevel):
list_top_level.add(ir.function)
if (
isinstance(ir, SolidityCall)
and isinstance(ir.function, SolidityCustomRevert)
and isinstance(ir.function.custom_error, TopLevel)
):
list_top_level.add(ir.function.custom_error)
list_contract.add(contract)
def _export_contract_with_inheritance(self, contract) -> Export:
list_contracts: List[Contract] = [] # will contain contract itself
list_top_level: List[TopLevel] = []
list_contracts: Set[Contract] = set() # will contain contract itself
list_top_level: Set[TopLevel] = set()
self._export_list_used_contracts(contract, set(), list_contracts, list_top_level)
path = Path(self._export_path, f"{contract.name}_{uuid.uuid4()}.sol")
@ -401,8 +408,8 @@ class Flattening:
def _export_with_import(self) -> List[Export]:
exports: List[Export] = []
for contract in self._compilation_unit.contracts:
list_contracts: List[Contract] = [] # will contain contract itself
list_top_level: List[TopLevel] = []
list_contracts: Set[Contract] = set() # will contain contract itself
list_top_level: Set[TopLevel] = set()
self._export_list_used_contracts(contract, set(), list_contracts, list_top_level)
if list_top_level:

@ -441,7 +441,7 @@ class SlitherReadStorage:
if "int" in key_type: # without this eth_utils encoding fails
key = int(key)
key = coerce_type(key_type, key)
slot = keccak(encode([key_type, "uint256"], [key, decode("uint256", slot)]))
slot = keccak(encode([key_type, "uint256"], [key, decode(["uint256"], slot)[0]]))
if isinstance(target_variable_type.type_to, UserDefinedType) and isinstance(
target_variable_type.type_to.type, Structure

@ -1,62 +1,149 @@
# Functions for generating Solidity code
from typing import TYPE_CHECKING, Optional
from slither.utils.type import convert_type_for_solidity_signature_to_string
from slither.utils.type import (
convert_type_for_solidity_signature_to_string,
export_nested_types_from_variable,
export_return_type_from_variable,
)
from slither.core.solidity_types import (
Type,
UserDefinedType,
MappingType,
ArrayType,
ElementaryType,
)
from slither.core.declarations import Structure, Enum, Contract
if TYPE_CHECKING:
from slither.core.declarations import FunctionContract, Structure, Contract
from slither.core.declarations import FunctionContract, CustomErrorContract
from slither.core.variables.state_variable import StateVariable
from slither.core.variables.local_variable import LocalVariable
def generate_interface(contract: "Contract") -> str:
# pylint: disable=too-many-arguments
def generate_interface(
contract: "Contract",
unroll_structs: bool = True,
include_events: bool = True,
include_errors: bool = True,
include_enums: bool = True,
include_structs: bool = True,
) -> str:
"""
Generates code for a Solidity interface to the contract.
Args:
contract: A Contract object
contract: A Contract object.
unroll_structs: Whether to use structures' underlying types instead of the user-defined type (default: True).
include_events: Whether to include event signatures in the interface (default: True).
include_errors: Whether to include custom error signatures in the interface (default: True).
include_enums: Whether to include enum definitions in the interface (default: True).
include_structs: Whether to include struct definitions in the interface (default: True).
Returns:
A string with the code for an interface, with function stubs for all public or external functions and
state variables, as well as any events, custom errors and/or structs declared in the contract.
"""
interface = f"interface I{contract.name} {{\n"
for event in contract.events:
name, args = event.signature
interface += f" event {name}({', '.join(args)});\n"
for error in contract.custom_errors:
args = [
convert_type_for_solidity_signature_to_string(arg.type)
.replace("(", "")
.replace(")", "")
for arg in error.parameters
]
interface += f" error {error.name}({', '.join(args)});\n"
for enum in contract.enums:
interface += f" enum {enum.name} {{ {', '.join(enum.values)} }}\n"
for struct in contract.structures:
interface += generate_struct_interface_str(struct)
if include_events:
for event in contract.events:
name, args = event.signature
interface += f" event {name}({', '.join(args)});\n"
if include_errors:
for error in contract.custom_errors:
interface += f" error {generate_custom_error_interface(error, unroll_structs)};\n"
if include_enums:
for enum in contract.enums:
interface += f" enum {enum.name} {{ {', '.join(enum.values)} }}\n"
if include_structs:
for struct in contract.structures:
interface += generate_struct_interface_str(struct, indent=4)
for var in contract.state_variables_entry_points:
interface += f" function {var.signature_str.replace('returns', 'external returns ')};\n"
interface += f" function {generate_interface_variable_signature(var, unroll_structs)};\n"
for func in contract.functions_entry_points:
if func.is_constructor or func.is_fallback or func.is_receive:
continue
interface += f" function {generate_interface_function_signature(func)};\n"
interface += (
f" function {generate_interface_function_signature(func, unroll_structs)};\n"
)
interface += "}\n\n"
return interface
def generate_interface_function_signature(func: "FunctionContract") -> Optional[str]:
def generate_interface_variable_signature(
var: "StateVariable", unroll_structs: bool = True
) -> Optional[str]:
if var.visibility in ["private", "internal"]:
return None
if unroll_structs:
params = [
convert_type_for_solidity_signature_to_string(x).replace("(", "").replace(")", "")
for x in export_nested_types_from_variable(var)
]
returns = [
convert_type_for_solidity_signature_to_string(x).replace("(", "").replace(")", "")
for x in export_return_type_from_variable(var)
]
else:
_, params, _ = var.signature
params = [p + " memory" if p in ["bytes", "string"] else p for p in params]
returns = []
_type = var.type
while isinstance(_type, MappingType):
_type = _type.type_to
while isinstance(_type, (ArrayType, UserDefinedType)):
_type = _type.type
ret = str(_type)
if isinstance(_type, Structure) or (isinstance(_type, Type) and _type.is_dynamic):
ret += " memory"
elif isinstance(_type, Contract):
ret = "address"
returns.append(ret)
return f"{var.name}({','.join(params)}) external returns ({', '.join(returns)})"
def generate_interface_function_signature(
func: "FunctionContract", unroll_structs: bool = True
) -> Optional[str]:
"""
Generates a string of the form:
func_name(type1,type2) external {payable/view/pure} returns (type3)
Args:
func: A FunctionContract object
unroll_structs: Determines whether structs are unrolled into underlying types (default: True)
Returns:
The function interface as a str (contains the return values).
Returns None if the function is private or internal, or is a constructor/fallback/receive.
"""
name, parameters, return_vars = func.signature
def format_var(var: "LocalVariable", unroll: bool) -> str:
if unroll:
return (
convert_type_for_solidity_signature_to_string(var.type)
.replace("(", "")
.replace(")", "")
)
if isinstance(var.type, ArrayType) and isinstance(
var.type.type, (UserDefinedType, ElementaryType)
):
return (
convert_type_for_solidity_signature_to_string(var.type)
.replace("(", "")
.replace(")", "")
+ f" {var.location}"
)
if isinstance(var.type, UserDefinedType):
if isinstance(var.type.type, (Structure, Enum)):
return f"{str(var.type.type)} memory"
if isinstance(var.type.type, Contract):
return "address"
if var.type.is_dynamic:
return f"{var.type} {var.location}"
return str(var.type)
name, _, _ = func.signature
if (
func not in func.contract.functions_entry_points
or func.is_constructor
@ -64,26 +151,20 @@ def generate_interface_function_signature(func: "FunctionContract") -> Optional[
or func.is_receive
):
return None
view = " view" if func.view else ""
view = " view" if func.view and not func.pure else ""
pure = " pure" if func.pure else ""
payable = " payable" if func.payable else ""
returns = [
convert_type_for_solidity_signature_to_string(ret.type).replace("(", "").replace(")", "")
for ret in func.returns
]
parameters = [
convert_type_for_solidity_signature_to_string(param.type).replace("(", "").replace(")", "")
for param in func.parameters
]
returns = [format_var(ret, unroll_structs) for ret in func.returns]
parameters = [format_var(param, unroll_structs) for param in func.parameters]
_interface_signature_str = (
name + "(" + ",".join(parameters) + ") external" + payable + pure + view
)
if len(return_vars) > 0:
if len(returns) > 0:
_interface_signature_str += " returns (" + ",".join(returns) + ")"
return _interface_signature_str
def generate_struct_interface_str(struct: "Structure") -> str:
def generate_struct_interface_str(struct: "Structure", indent: int = 0) -> str:
"""
Generates code for a structure declaration in an interface of the form:
struct struct_name {
@ -92,13 +173,37 @@ def generate_struct_interface_str(struct: "Structure") -> str:
... ...
}
Args:
struct: A Structure object
struct: A Structure object.
indent: Number of spaces to indent the code block with.
Returns:
The structure declaration code as a string.
"""
definition = f" struct {struct.name} {{\n"
spaces = ""
for _ in range(0, indent):
spaces += " "
definition = f"{spaces}struct {struct.name} {{\n"
for elem in struct.elems_ordered:
definition += f" {elem.type} {elem.name};\n"
definition += " }\n"
if isinstance(elem.type, UserDefinedType):
if isinstance(elem.type.type, (Structure, Enum)):
definition += f"{spaces} {elem.type.type} {elem.name};\n"
elif isinstance(elem.type.type, Contract):
definition += f"{spaces} address {elem.name};\n"
else:
definition += f"{spaces} {elem.type} {elem.name};\n"
definition += f"{spaces}}}\n"
return definition
def generate_custom_error_interface(
error: "CustomErrorContract", unroll_structs: bool = True
) -> str:
args = [
convert_type_for_solidity_signature_to_string(arg.type).replace("(", "").replace(")", "")
if unroll_structs
else str(arg.type.type)
if isinstance(arg.type, UserDefinedType) and isinstance(arg.type.type, (Structure, Enum))
else str(arg.type)
for arg in error.parameters
]
return f"{error.name}({', '.join(args)})"

@ -1,6 +1,6 @@
from typing import List, Dict, Union
from prettytable import PrettyTable
from prettytable.colortable import ColorTable, Themes
class MyPrettyTable:
@ -11,8 +11,8 @@ class MyPrettyTable:
def add_row(self, row: List[Union[str, List[str]]]) -> None:
self._rows.append(row)
def to_pretty_table(self) -> PrettyTable:
table = PrettyTable(self._field_names)
def to_pretty_table(self) -> ColorTable:
table = ColorTable(self._field_names, theme=Themes.OCEAN)
for row in self._rows:
table.add_row(row)
return table

@ -197,3 +197,18 @@ def export_return_type_from_variable(
return ret
return [variable_or_type.type]
def is_underlying_type_address(t: "Type") -> bool:
"""
Return true if the underlying type is an address
i.e. if the type is an address or a contract
"""
# pylint: disable=import-outside-toplevel
from slither.core.declarations.contract import Contract
if t == ElementaryType("address"):
return True
if isinstance(t, UserDefinedType) and isinstance(t.type, Contract):
return True
return False

@ -626,7 +626,6 @@ class ExpressionToSlithIR(ExpressionVisitor):
set_val(expression, value)
elif expression.type in [UnaryOperationType.MINUS_PRE]:
lvalue = TemporaryVariable(self._node)
assert isinstance(value.type, ElementaryType)
operation = Binary(lvalue, Constant("0", value.type), value, BinaryType.SUBTRACTION)
operation.set_expression(expression)
self._result.append(operation)

@ -0,0 +1,15 @@
EncodePackedCollision.bad4(bytes,bytes) (tests/e2e/detectors/test_data/encode-packed-collision/0.7.6/encode_packed_collision.sol#34-36) calls abi.encodePacked() with multiple dynamic arguments:
- packed = abi.encodePacked(a,a2,a3,a) (tests/e2e/detectors/test_data/encode-packed-collision/0.7.6/encode_packed_collision.sol#35)
EncodePackedCollision.bad2(string,uint256[]) (tests/e2e/detectors/test_data/encode-packed-collision/0.7.6/encode_packed_collision.sol#24-26) calls abi.encodePacked() with multiple dynamic arguments:
- packed = abi.encodePacked(stra,arra) (tests/e2e/detectors/test_data/encode-packed-collision/0.7.6/encode_packed_collision.sol#25)
EncodePackedCollision.bad3_get_hash_for_signature(string,string) (tests/e2e/detectors/test_data/encode-packed-collision/0.7.6/encode_packed_collision.sol#29-31) calls abi.encodePacked() with multiple dynamic arguments:
- keccak256(bytes)(abi.encodePacked(name,doc)) (tests/e2e/detectors/test_data/encode-packed-collision/0.7.6/encode_packed_collision.sol#30)
EncodePackedCollision.bad0(string,string) (tests/e2e/detectors/test_data/encode-packed-collision/0.7.6/encode_packed_collision.sol#14-16) calls abi.encodePacked() with multiple dynamic arguments:
- packed = abi.encodePacked(stra,strb) (tests/e2e/detectors/test_data/encode-packed-collision/0.7.6/encode_packed_collision.sol#15)
EncodePackedCollision.bad1(string,bytes) (tests/e2e/detectors/test_data/encode-packed-collision/0.7.6/encode_packed_collision.sol#19-21) calls abi.encodePacked() with multiple dynamic arguments:
- packed = abi.encodePacked(stra,bytesa) (tests/e2e/detectors/test_data/encode-packed-collision/0.7.6/encode_packed_collision.sol#20)

@ -1,2 +1,2 @@
C.f() (tests/e2e/detectors/test_data/incorrect-shift/0.7.6/shift_parameter_mixup.sol#3-7) contains an incorrect shift operation: a = 8 >> a (tests/e2e/detectors/test_data/incorrect-shift/0.7.6/shift_parameter_mixup.sol#5)
C.f() (tests/e2e/detectors/test_data/incorrect-shift/0.7.6/shift_parameter_mixup.sol#3-8) contains an incorrect shift operation: a = 8 >> a (tests/e2e/detectors/test_data/incorrect-shift/0.7.6/shift_parameter_mixup.sol#5)

@ -1,4 +1,8 @@
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol#17-29) ignores return value by t.f() (tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol#18)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol#18-37) ignores return value by t.g() (tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol#31)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol#17-29) ignores return value by a.add(0) (tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol#22)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol#18-37) ignores return value by t.f() (tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol#19)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol#18-37) ignores return value by a.add(0) (tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol#23)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol#18-37) ignores return value by (e) = t.g() (tests/e2e/detectors/test_data/unused-return/0.4.25/unused_return.sol#36)

@ -1,4 +1,8 @@
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol#17-29) ignores return value by t.f() (tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol#18)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol#18-37) ignores return value by (e) = t.g() (tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol#36)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol#17-29) ignores return value by a.add(0) (tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol#22)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol#18-37) ignores return value by a.add(0) (tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol#23)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol#18-37) ignores return value by t.g() (tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol#31)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol#18-37) ignores return value by t.f() (tests/e2e/detectors/test_data/unused-return/0.5.16/unused_return.sol#19)

@ -1,4 +1,8 @@
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol#17-29) ignores return value by a.add(0) (tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol#22)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol#18-37) ignores return value by t.f() (tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol#19)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol#17-29) ignores return value by t.f() (tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol#18)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol#18-37) ignores return value by a.add(0) (tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol#23)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol#18-37) ignores return value by t.g() (tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol#31)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol#18-37) ignores return value by (e) = t.g() (tests/e2e/detectors/test_data/unused-return/0.6.11/unused_return.sol#36)

@ -1,4 +1,8 @@
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol#17-29) ignores return value by a.add(0) (tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol#22)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol#18-37) ignores return value by t.g() (tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol#31)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol#17-29) ignores return value by t.f() (tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol#18)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol#18-37) ignores return value by a.add(0) (tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol#23)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol#18-37) ignores return value by t.f() (tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol#19)
User.test(Target) (tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol#18-37) ignores return value by (e) = t.g() (tests/e2e/detectors/test_data/unused-return/0.7.6/unused_return.sol#36)

@ -0,0 +1,78 @@
contract ABIencodePacked{
uint a;
string str1 = "a";
string str2 = "bc";
bytes _bytes = "hello world";
uint[] arr;
uint[2] arr2;
string[3] str_arr3; /* This nested dynamic type is not supported in abi.encodePacked mode by solc */
string[] str_array; /* This nested dynamic type is not supported in abi.encodePacked mode by solc */
bytes[] bytes_array; /* This nested dynamic type and tuples are not supported in abi.encodePacked mode by solc */
/* Two dynamic types */
function bad0(string calldata stra, string calldata strb) external{
bytes memory packed = abi.encodePacked(stra, strb);
}
/* Two dynamic types */
function bad1(string calldata stra, bytes calldata bytesa) external{
bytes memory packed = abi.encodePacked(stra, bytesa);
}
/* Two dynamic types */
function bad2(string calldata stra, uint[] calldata arra) external{
bytes memory packed = abi.encodePacked(stra, arra);
}
/* Two dynamic types */
function bad3_get_hash_for_signature(string calldata name, string calldata doc) external returns (bytes32) {
return keccak256(abi.encodePacked(name, doc));
}
/* Two dynamic types between non dynamic types */
function bad4(bytes calldata a2, bytes calldata a3) external {
bytes memory packed = abi.encodePacked(a, a2, a3, a);
}
/* Two dynamic types but static values*/
function good0() external{
bytes memory packed = abi.encodePacked(str1, str2);
}
/* Two dynamic types but static values*/
function good1() external{
bytes memory packed = abi.encodePacked(str1, _bytes);
}
/* Two dynamic types but static values*/
function good2() external{
bytes memory packed = abi.encodePacked(str1, arr);
}
/* No dynamic types */
function good3() external{
bytes memory packed = abi.encodePacked(a);
}
/* One dynamic type */
function good4() external{
bytes memory packed = abi.encodePacked(str1);
}
/* One dynamic type */
function good5() external{
bytes memory packed = abi.encodePacked(a, str1);
}
/* One dynamic type */
function good6() external{
bytes memory packed = abi.encodePacked(str1, arr2);
}
/* Two dynamic types but not consecutive*/
function good7(string calldata a, uint b, string calldata c) external{
bytes memory packed = abi.encodePacked(a, b, c);
}
}

@ -134,3 +134,27 @@ contract TestSolidityKeyword{
}
interface Receiver {
}
contract A {
mapping(address => Info) data;
struct Info {
uint a;
address b;
uint c;
}
function good(address b) public payable {
data[msg.sender] = Info(block.timestamp, b, msg.value);
if (data[msg.sender].b == address(0)) {
payable(msg.sender).transfer(data[msg.sender].c);
}
}
function good2(address b) public payable {
data[msg.sender] = Info(block.timestamp, b, msg.value);
if (Receiver(data[msg.sender].b) == Receiver(address(0))) {
payable(msg.sender).transfer(data[msg.sender].c);
}
}
}

@ -1,8 +1,9 @@
contract C {
function f() internal returns (uint a) {
function f() internal returns (uint a, uint b) {
assembly {
a := shr(a, 8)
b := shl(248, 0xff)
}
}
}

@ -8,6 +8,7 @@ library SafeMath{
contract Target{
function f() public returns(uint);
function g() public returns(uint, uint);
}
contract User{
@ -26,5 +27,12 @@ contract User{
// As the value returned by the call is stored
// (unused local variable should be another issue)
uint b = a.add(1);
t.g();
(uint c, uint d) = t.g();
// Detected as unused return
(uint e,) = t.g();
}
}

@ -8,6 +8,7 @@ library SafeMath{
contract Target{
function f() public returns(uint);
function g() public returns(uint, uint);
}
contract User{
@ -26,5 +27,12 @@ contract User{
// As the value returned by the call is stored
// (unused local variable should be another issue)
uint b = a.add(1);
t.g();
(uint c, uint d) = t.g();
// Detected as unused return
(uint e,) = t.g();
}
}

@ -8,6 +8,7 @@ library SafeMath{
abstract contract Target{
function f() public virtual returns(uint);
function g() public virtual returns(uint, uint);
}
contract User{
@ -26,5 +27,12 @@ contract User{
// As the value returned by the call is stored
// (unused local variable should be another issue)
uint b = a.add(1);
t.g();
(uint c, uint d) = t.g();
// Detected as unused return
(uint e,) = t.g();
}
}

@ -8,6 +8,7 @@ library SafeMath{
abstract contract Target{
function f() public virtual returns(uint);
function g() public virtual returns(uint, uint);
}
contract User{
@ -26,5 +27,12 @@ contract User{
// As the value returned by the call is stored
// (unused local variable should be another issue)
uint b = a.add(1);
t.g();
(uint c, uint d) = t.g();
// Detected as unused return
(uint e,) = t.g();
}
}

@ -1639,6 +1639,11 @@ ALL_TEST_OBJECTS = [
"LowCyclomaticComplexity.sol",
"0.8.16",
),
Test(
all_detectors.EncodePackedCollision,
"encode_packed_collision.sol",
"0.7.6",
),
]
GENERIC_PATH = "/GENERIC_PATH"

@ -452,6 +452,7 @@ ALL_TESTS = [
Test("yul-top-level-0.8.0.sol", ["0.8.0"]),
Test("complex_imports/import_aliases_issue_1319/test.sol", ["0.5.12"]),
Test("yul-state-constant-access.sol", ["0.8.16"]),
Test("negate-unary-element.sol", ["0.8.16"]),
]
# create the output folder if needed
try:

@ -1,5 +1,12 @@
contract C {
function f() public {
modifier a() {
assembly {
let y := 0
}
_;
}
function f() public a {
assembly {
let x := 0
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save