Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5876ef1
Add entry_points printer to all_printers.py list
nisedo Dec 12, 2024
2ca5f2d
Update README to add entry-points printer
nisedo Dec 12, 2024
3aef721
Add entry_points.py printer
nisedo Dec 12, 2024
91230d3
Refactor entry_points.py for linters and correct README
nisedo Dec 13, 2024
8b99d57
Fix assertion error
smonicas Jan 20, 2025
cc15939
Fix detectors wiki links
smonicas Jan 20, 2025
769245c
Bump pypa/gh-action-pypi-publish from 1.12.3 to 1.12.4
dependabot[bot] Jan 27, 2025
7f046a2
Merge branch 'dev' into dev
nisedo Jan 30, 2025
f28da4d
Merge pull request #2640 from crytic/dev-fix-wiki-links
montyly Jan 31, 2025
2bbddf2
Merge pull request #2639 from crytic/dev-fix-pyth
montyly Jan 31, 2025
c36ed42
Merge pull request #2649 from crytic/dependabot/github_actions/dev/py…
montyly Jan 31, 2025
0a93888
Fix array .push and .pop edge cases
smonicas Jan 31, 2025
c61d06b
Update CLI --verbose description
smonicas Jan 31, 2025
cacf6f6
Merge pull request #2653 from crytic/dev-fix-AOR-mutator
montyly Jan 31, 2025
9292ecb
Merge branch 'crytic:dev' into dev
nisedo Feb 1, 2025
29a8a41
Refactoring following Simone's feedback
nisedo Feb 1, 2025
0362717
Change file name format
nisedo Feb 1, 2025
cc88216
Use f.is_shadowed to handle correctly virtual and override functions
nisedo Feb 2, 2025
0d2d548
Add receive/fallback. Add contract lines. Add function arguments and …
nisedo Feb 2, 2025
a75b1f6
Update README.md
hexshire Feb 3, 2025
61fa9ec
Merge pull request #2616 from nisedo/dev
smonicas Feb 3, 2025
f6413e6
Merge pull request #2656 from hexshire/patch-1
smonicas Feb 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
path: dist/

- name: publish
uses: pypa/[email protected].3
uses: pypa/[email protected].4

- name: sign
uses: sigstore/[email protected]
Expand Down
23 changes: 15 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ python3 -m pip install slither-analyzer
python3 -m pip install --upgrade slither-analyzer
```

### Using Brew

```console
brew install slither-analyzer
```

### Using Git

```bash
Expand Down Expand Up @@ -159,7 +165,7 @@ Num | Detector | What it Detects | Impact | Confidence
35 | `locked-ether` | [Contracts that lock ether](https://github.com/crytic/slither/wiki/Detector-Documentation#contracts-that-lock-ether) | Medium | High
36 | `mapping-deletion` | [Deletion on mapping containing a structure](https://github.com/crytic/slither/wiki/Detector-Documentation#deletion-on-mapping-containing-a-structure) | Medium | High
37 | `pyth-deprecated-functions` | [Detect Pyth deprecated functions](https://github.com/crytic/slither/wiki/Detector-Documentation#pyth-deprecated-functions) | Medium | High
38 | `pyth-unchecked-confidence` | [Detect when the confidence level of a Pyth price is not checked](https://github.com/crytic/slither/wiki/Detector-Documentation#pyth-unchecked-confidence) | Medium | High
38 | `pyth-unchecked-confidence` | [Detect when the confidence level of a Pyth price is not checked](https://github.com/crytic/slither/wiki/Detector-Documentation#pyth-unchecked-confidence-level) | Medium | High
39 | `pyth-unchecked-publishtime` | [Detect when the publishTime of a Pyth price is not checked](https://github.com/crytic/slither/wiki/Detector-Documentation#pyth-unchecked-publishtime) | Medium | High
40 | `shadowing-abstract` | [State variables shadowing from abstract contracts](https://github.com/crytic/slither/wiki/Detector-Documentation#state-variable-shadowing-from-abstract-contracts) | Medium | High
41 | `tautological-compare` | [Comparing a variable to itself always returns true or false, depending on comparison](https://github.com/crytic/slither/wiki/Detector-Documentation#tautological-compare) | Medium | High
Expand All @@ -179,9 +185,9 @@ Num | Detector | What it Detects | Impact | Confidence
55 | `unchecked-send` | [Unchecked send](https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-send) | Medium | Medium
56 | `uninitialized-local` | [Uninitialized local variables](https://github.com/crytic/slither/wiki/Detector-Documentation#uninitialized-local-variables) | Medium | Medium
57 | `unused-return` | [Unused return values](https://github.com/crytic/slither/wiki/Detector-Documentation#unused-return) | Medium | Medium
58 | `chainlink-feed-registry` | [Detect when chainlink feed registry is used](https://github.com/crytic/slither/wiki/Detector-Documentation#chainlink-feed-registry) | Low | High
58 | `chainlink-feed-registry` | [Detect when chainlink feed registry is used](https://github.com/crytic/slither/wiki/Detector-Documentation#chainlink-feed-registry-usage) | Low | High
59 | `incorrect-modifier` | [Modifiers that can return the default value](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-modifier) | Low | High
60 | `optimism-deprecation` | [Detect when deprecated Optimism predeploy or function is used.](https://github.com/crytic/slither/wiki/Detector-Documentation#optimism-deprecation) | Low | High
60 | `optimism-deprecation` | [Detect when deprecated Optimism predeploy or function is used.](https://github.com/crytic/slither/wiki/Detector-Documentation#optimism-deprecated-predeploy-or-function) | Low | High
61 | `shadowing-builtin` | [Built-in symbol shadowing](https://github.com/crytic/slither/wiki/Detector-Documentation#builtin-symbol-shadowing) | Low | High
62 | `shadowing-local` | [Local variables shadowing](https://github.com/crytic/slither/wiki/Detector-Documentation#local-variable-shadowing) | Low | High
63 | `uninitialized-fptr-cst` | [Uninitialized function pointer calls in constructors](https://github.com/crytic/slither/wiki/Detector-Documentation#uninitialized-function-pointers-in-constructors) | Low | High
Expand All @@ -203,7 +209,7 @@ Num | Detector | What it Detects | Impact | Confidence
79 | `deprecated-standards` | [Deprecated Solidity Standards](https://github.com/crytic/slither/wiki/Detector-Documentation#deprecated-standards) | Informational | High
80 | `erc20-indexed` | [Un-indexed ERC20 event parameters](https://github.com/crytic/slither/wiki/Detector-Documentation#unindexed-erc20-event-parameters) | Informational | High
81 | `function-init-state` | [Function initializing state variables](https://github.com/crytic/slither/wiki/Detector-Documentation#function-initializing-state) | Informational | High
82 | `incorrect-using-for` | [Detects using-for statement usage when no function from a given library matches a given type](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-using-for-usage) | Informational | High
82 | `incorrect-using-for` | [Detects using-for statement usage when no function from a given library matches a given type](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-usage-of-using-for-statement) | Informational | High
83 | `low-level-calls` | [Low level calls](https://github.com/crytic/slither/wiki/Detector-Documentation#low-level-calls) | Informational | High
84 | `missing-inheritance` | [Missing inheritance](https://github.com/crytic/slither/wiki/Detector-Documentation#missing-inheritance) | Informational | High
85 | `naming-convention` | [Conformity to Solidity naming conventions](https://github.com/crytic/slither/wiki/Detector-Documentation#conformance-to-solidity-naming-conventions) | Informational | High
Expand Down Expand Up @@ -232,10 +238,11 @@ For more information, see

### Quick Review Printers

* `human-summary`: [Print a human-readable summary of the contracts](https://github.com/crytic/slither/wiki/Printer-documentation#human-summary)
* `inheritance-graph`: [Export the inheritance graph of each contract to a dot file](https://github.com/crytic/slither/wiki/Printer-documentation#inheritance-graph)
* `contract-summary`: [Print a summary of the contracts](https://github.com/crytic/slither/wiki/Printer-documentation#contract-summary)
* `loc`: [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).](https://github.com/crytic/slither/wiki/Printer-documentation#loc)
* `human-summary`: [Print a human-readable summary of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#human-summary)
* `inheritance-graph`: [Export the inheritance graph of each contract to a dot file](https://github.com/trailofbits/slither/wiki/Printer-documentation#inheritance-graph)
* `contract-summary`: [Print a summary of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#contract-summary)
* `loc`: [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).](https://github.com/trailofbits/slither/wiki/Printer-documentation#loc)
* `entry-points`: [Print all the state-changing entry point functions of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#entry-points)

### In-Depth Review Printers

Expand Down
2 changes: 1 addition & 1 deletion slither/detectors/functions/chainlink_feed_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class ChainlinkFeedRegistry(AbstractDetector):
IMPACT = DetectorClassification.LOW
CONFIDENCE = DetectorClassification.HIGH

WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#chainlink-feed-registry"
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#chainlink-feed-registry-usage"

WIKI_TITLE = "Chainlink Feed Registry usage"
WIKI_DESCRIPTION = "Detect when Chainlink Feed Registry is used. At the moment is only available on Ethereum Mainnet."
Expand Down
2 changes: 1 addition & 1 deletion slither/detectors/functions/optimism_deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class OptimismDeprecation(AbstractDetector):
IMPACT = DetectorClassification.LOW
CONFIDENCE = DetectorClassification.HIGH

WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#optimism-deprecation"
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#optimism-deprecated-predeploy-or-function"

WIKI_TITLE = "Optimism deprecated predeploy or function"
WIKI_DESCRIPTION = "Detect when deprecated Optimism predeploy or function is used."
Expand Down
2 changes: 1 addition & 1 deletion slither/detectors/statements/incorrect_using_for.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class IncorrectUsingFor(AbstractDetector):
IMPACT = DetectorClassification.INFORMATIONAL
CONFIDENCE = DetectorClassification.HIGH

WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-using-for-usage"
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-usage-of-using-for-statement"

WIKI_TITLE = "Incorrect usage of using-for statement"
WIKI_DESCRIPTION = (
Expand Down
6 changes: 3 additions & 3 deletions slither/detectors/statements/pyth_unchecked.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ def _detect(self) -> List[Output]:
for contract in self.compilation_unit.contracts_derived:
for target_contract, ir in contract.all_high_level_calls:
if target_contract.name == "IPyth" and ir.function_name in self.PYTH_FUNCTIONS:
# We know for sure the second IR in the node is an Assignment operation of the TMP variable. Example:
# We know for sure the last IR in the node is an Assignment operation of the TMP variable. Example:
# Expression: price = pyth.getEmaPriceNoOlderThan(id,age)
# IRs:
# TMP_0(PythStructs.Price) = HIGH_LEVEL_CALL, dest:pyth(IPyth), function:getEmaPriceNoOlderThan, arguments:['id', 'age']
# price(PythStructs.Price) := TMP_0(PythStructs.Price)
assert isinstance(ir.node.irs[1], Assignment)
return_variable = ir.node.irs[1].lvalue
assert isinstance(ir.node.irs[len(ir.node.irs) - 1], Assignment)
return_variable = ir.node.irs[len(ir.node.irs) - 1].lvalue
checked = False

possible_unchecked_variable_ir = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class PythUncheckedConfidence(PythUnchecked):
IMPACT = DetectorClassification.MEDIUM
CONFIDENCE = DetectorClassification.HIGH

WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#pyth-unchecked-confidence"
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#pyth-unchecked-confidence-level"
WIKI_TITLE = "Pyth unchecked confidence level"
WIKI_DESCRIPTION = "Detect when the confidence level of a Pyth price is not checked"
WIKI_RECOMMENDATION = "Check the confidence level of a Pyth price. Visit https://docs.pyth.network/price-feeds/best-practices#confidence-intervals for more information."
Expand Down
1 change: 1 addition & 0 deletions slither/printers/all_printers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@
from .functions.dominator import Dominator
from .summary.martin import Martin
from .summary.cheatcodes import CheatcodePrinter
from .summary.entry_points import PrinterEntryPoints
94 changes: 94 additions & 0 deletions slither/printers/summary/entry_points.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"""
Module printing all the state-changing entry point functions of the contracts
"""

from slither.printers.abstract_printer import AbstractPrinter
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.colors import Colors
from slither.utils.output import Output
from slither.utils.myprettytable import MyPrettyTable


class PrinterEntryPoints(AbstractPrinter):

ARGUMENT = "entry-points"
HELP = "Print all the state-changing entry point functions of the contracts"

WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#entry-points"

def output(self, _filename) -> Output:
"""
_filename is not used
Args:
_filename(string)
"""
all_contracts = []

for contract in sorted(
(
c
for c in self.contracts
if not c.is_interface
and not c.is_library
and not c.is_abstract
and "lib/" not in c.source_mapping.filename.absolute
and "node_modules/" not in c.source_mapping.filename.absolute
and not any(
mock in c.source_mapping.filename.absolute.lower() for mock in ["mock", "mocks"]
)
),
key=lambda x: x.name,
):
entry_points = [
f
for f in contract.functions
if (
f.visibility in ["public", "external"]
and isinstance(f, FunctionContract)
and not f.is_constructor
and not f.view
and not f.pure
and not f.contract_declarer.is_interface
and not f.contract_declarer.is_library
and not f.is_shadowed
)
]

if not entry_points:
continue

table = MyPrettyTable(["Function", "Modifiers", "Inherited From"])
contract_info = [
f"\nContract {Colors.BOLD}{Colors.YELLOW}{contract.name}{Colors.END}"
f" ({contract.source_mapping})"
]

for f in sorted(
entry_points,
key=lambda x: (x.visibility != "external", x.visibility != "public", x.full_name),
):
modifier_list = [m.name for m in f.modifiers]
if f.payable:
modifier_list.append("payable")
modifiers = ", ".join(modifier_list) if modifier_list else ""
inherited = f"{f.contract_declarer.name}" if f.contract_declarer != contract else ""

name_parts = f.full_name.split("(", 1)
function_name = (
f"{Colors.BOLD}{Colors.RED}{name_parts[0]}{Colors.END}" f"({name_parts[1]}"
)

table.add_row(
[
function_name,
f"{Colors.GREEN}{modifiers}{Colors.END}" if modifiers else "",
f"{Colors.MAGENTA}{inherited}{Colors.END}" if inherited else "",
]
)

contract_info.append(str(table))
all_contracts.append("\n".join(contract_info))

info = "\n".join(all_contracts) if all_contracts else ""
self.info(info)
return self.generate_output(info)
3 changes: 1 addition & 2 deletions slither/tools/mutator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ options:
--timeout TIMEOUT Set timeout for test command (by default 30 seconds)
--output-dir OUTPUT_DIR
Name of output directory (by default 'mutation_campaign')
-v, --verbose log mutants that are caught as well as those that are uncaught
-vv, --very-verbose log mutants that are caught, uncaught, and fail to compile. And more!
-v, --verbose log mutants that are caught, uncaught, and fail to compile
--mutators-to-run MUTATORS_TO_RUN
mutant generators to run
--contract-names CONTRACT_NAMES
Expand Down
2 changes: 1 addition & 1 deletion slither/tools/mutator/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def parse_args() -> argparse.Namespace:
parser.add_argument(
"-v",
"--verbose",
help="log mutants that are caught as well as those that are uncaught",
help="log mutants that are caught, uncaught, and fail to compile",
action="store_true",
default=False,
)
Expand Down
9 changes: 0 additions & 9 deletions slither/tools/mutator/mutators/AOR.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@
from slither.slithir.operations import Binary, BinaryType
from slither.tools.mutator.utils.patch import create_patch_with_line
from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator
from slither.core.variables.variable import Variable
from slither.core.expressions.unary_operation import UnaryOperation
from slither.core.expressions.call_expression import CallExpression
from slither.core.expressions.member_access import MemberAccess
from slither.core.expressions.identifier import Identifier
from slither.core.solidity_types.array_type import ArrayType

arithmetic_operators = [
BinaryType.ADDITION,
Expand Down Expand Up @@ -42,9 +39,6 @@ def _mutate(self) -> Dict:
isinstance(ir_expression, CallExpression)
and isinstance(ir_expression.called, MemberAccess)
and ir_expression.called.member_name == "pop"
and isinstance(ir_expression.called.expression, Identifier)
and isinstance(ir_expression.called.expression.value, Variable)
and isinstance(ir_expression.called.expression.value.type, ArrayType)
):
continue

Expand All @@ -58,9 +52,6 @@ def _mutate(self) -> Dict:
if isinstance(ir_expression, CallExpression)
and isinstance(ir_expression.called, MemberAccess)
and ir_expression.called.member_name == "push"
and isinstance(ir_expression.called.expression, Identifier)
and isinstance(ir_expression.called.expression.value, Variable)
and isinstance(ir_expression.called.expression.value.type, ArrayType)
else node.irs
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Pyth price conf field is not checked in C.bad(bytes32,uint256) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#171-175)
- price = pyth.getEmaPriceNoOlderThan(id,age) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#172)
Pyth price conf field is not checked in C.bad2(C.Data) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#182-186)
- price = pyth.getEmaPriceNoOlderThan(data.id,data.age) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#183)

Pyth price conf field is not checked in C.bad(bytes32,uint256) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#176-180)
- price = pyth.getEmaPriceNoOlderThan(id,age) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#177)

Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Pyth price publishTime field is not checked in C.bad(bytes32) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#171-175)
- price = pyth.getEmaPriceUnsafe(id) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#172)
Pyth price publishTime field is not checked in C.bad(bytes32) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#175-179)
- price = pyth.getEmaPriceUnsafe(id) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#176)

Pyth price publishTime field is not checked in C.bad2(C.Data) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#181-185)
- price = pyth.getEmaPriceUnsafe(data.id) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#182)

Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ interface IPyth {
contract C {
IPyth pyth;

struct Data {
bytes32 id;
uint256 age;
}

constructor(IPyth _pyth) {
pyth = _pyth;
}
Expand All @@ -174,6 +179,12 @@ contract C {
// Use price
}

function bad2(Data calldata data) public {
PythStructs.Price memory price = pyth.getEmaPriceNoOlderThan(data.id, data.age);
require(price.publishTime > block.timestamp - 120);
// Use price
}

function good(bytes32 id, uint256 age) public {
PythStructs.Price memory price = pyth.getEmaPriceNoOlderThan(id, age);
require(price.conf < 10000);
Expand Down
Binary file not shown.
Loading
Loading