Skip to content

Commit

Permalink
Merge pull request #838 from crytic/dev-dead-code
Browse files Browse the repository at this point in the history
Open source dead-code detector
  • Loading branch information
montyly authored Apr 30, 2021
2 parents ac5cee7 + cde06f4 commit ffbb62b
Show file tree
Hide file tree
Showing 7 changed files with 337 additions and 56 deletions.
111 changes: 56 additions & 55 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion slither/core/declarations/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ def functions_entry_points(self) -> List["FunctionContract"]:
return [
f
for f in self.functions
if f.visibility in ["public", "external"] and not f.is_shadowed
if f.visibility in ["public", "external"] and not f.is_shadowed or f.is_fallback
]

@property
Expand Down
1 change: 1 addition & 0 deletions slither/detectors/all_detectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
from .variables.predeclaration_usage_local import PredeclarationUsageLocal
from .statements.unary import IncorrectUnaryExpressionDetection
from .operations.missing_zero_address_validation import MissingZeroAddressValidation
from .functions.dead_code import DeadCode

#
#
72 changes: 72 additions & 0 deletions slither/detectors/functions/dead_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""
Module detecting dead code
"""
from typing import List, Tuple

from slither.core.declarations import Function, FunctionContract, Contract
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification


class DeadCode(AbstractDetector):
"""
Unprotected function detector
"""

ARGUMENT = "dead-code"
HELP = "Functions that are not used"
IMPACT = DetectorClassification.INFORMATIONAL
CONFIDENCE = DetectorClassification.MEDIUM

WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#dead-code"

WIKI_TITLE = "Dead-code"
WIKI_DESCRIPTION = "Functions that are not sued."
WIKI_EXPLOIT_SCENARIO = """
```solidity
contract Contract{
function dead_code() internal() {}
}
```
`dead_code` is not used in the contract, and make the code's review more difficult."""

WIKI_RECOMMENDATION = "Remove unused functions."

def _detect(self):

results = []

functions_used = set()
for contract in self.compilation_unit.contracts_derived:
all_functionss_called = [
f.all_internal_calls() for f in contract.functions_entry_points
]
all_functions_called = [item for sublist in all_functionss_called for item in sublist]
functions_used |= {
f.canonical_name for f in all_functions_called if isinstance(f, Function)
}
all_libss_called = [f.all_library_calls() for f in contract.functions_entry_points]
all_libs_called: List[Tuple[Contract, Function]] = [
item for sublist in all_libss_called for item in sublist
]
functions_used |= {
lib[1].canonical_name for lib in all_libs_called if isinstance(lib, tuple)
}
for function in sorted(self.compilation_unit.functions, key=lambda x: x.canonical_name):
if (
function.visibility in ["public", "external"]
or function.is_constructor
or function.is_fallback
or function.is_constructor_variables
):
continue
if function.canonical_name in functions_used:
continue
if isinstance(function, FunctionContract) and (
function.contract_declarer.is_from_dependency()
):
continue
info = [function, " is never used and should be removed\n"]
res = self.generate_result(info)
results.append(res)

return results
29 changes: 29 additions & 0 deletions tests/detectors/dead-code/0.8.0/dead-code.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
contract Test{
function unused() internal{

}
}


contract Test2{

function unused_but_shadowed() internal virtual{

}
}

contract Test3 is Test2{
function unused_but_shadowed() internal override{

}

function f() public{
unused_but_shadowed();
}
}

contract Test4 is Test2{
function unused_but_shadowed() internal override{

}
}
173 changes: 173 additions & 0 deletions tests/detectors/dead-code/0.8.0/dead-code.sol.0.8.0.DeadCode.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
[
[
{
"elements": [
{
"type": "function",
"name": "unused",
"source_mapping": {
"start": 19,
"length": 34,
"filename_used": "/GENERIC_PATH",
"filename_relative": "tests/detectors/dead-code/0.8.0/dead-code.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/dead-code/0.8.0/dead-code.sol",
"is_dependency": false,
"lines": [
2,
3,
4
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Test",
"source_mapping": {
"start": 0,
"length": 55,
"filename_used": "/GENERIC_PATH",
"filename_relative": "tests/detectors/dead-code/0.8.0/dead-code.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/dead-code/0.8.0/dead-code.sol",
"is_dependency": false,
"lines": [
1,
2,
3,
4,
5
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "unused()"
}
}
],
"description": "Test.unused() (tests/detectors/dead-code/0.8.0/dead-code.sol#2-4) is never used and should be removed\n",
"markdown": "[Test.unused()](tests/detectors/dead-code/0.8.0/dead-code.sol#L2-L4) is never used and should be removed\n",
"first_markdown_element": "tests/detectors/dead-code/0.8.0/dead-code.sol#L2-L4",
"id": "a7c13823116566bbbbb68e8a7efa78fe64785fcb8582069373eda7f27c523cb3",
"check": "dead-code",
"impact": "Informational",
"confidence": "Medium"
},
{
"elements": [
{
"type": "function",
"name": "unused_but_shadowed",
"source_mapping": {
"start": 79,
"length": 55,
"filename_used": "/GENERIC_PATH",
"filename_relative": "tests/detectors/dead-code/0.8.0/dead-code.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/dead-code/0.8.0/dead-code.sol",
"is_dependency": false,
"lines": [
10,
11,
12
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Test2",
"source_mapping": {
"start": 58,
"length": 78,
"filename_used": "/GENERIC_PATH",
"filename_relative": "tests/detectors/dead-code/0.8.0/dead-code.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/dead-code/0.8.0/dead-code.sol",
"is_dependency": false,
"lines": [
8,
9,
10,
11,
12,
13
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "unused_but_shadowed()"
}
}
],
"description": "Test2.unused_but_shadowed() (tests/detectors/dead-code/0.8.0/dead-code.sol#10-12) is never used and should be removed\n",
"markdown": "[Test2.unused_but_shadowed()](tests/detectors/dead-code/0.8.0/dead-code.sol#L10-L12) is never used and should be removed\n",
"first_markdown_element": "tests/detectors/dead-code/0.8.0/dead-code.sol#L10-L12",
"id": "aaba496684b73955e90b555de174e1cd03f0fee337849c4d58c10ef76ff93582",
"check": "dead-code",
"impact": "Informational",
"confidence": "Medium"
},
{
"elements": [
{
"type": "function",
"name": "unused_but_shadowed",
"source_mapping": {
"start": 319,
"length": 56,
"filename_used": "/GENERIC_PATH",
"filename_relative": "tests/detectors/dead-code/0.8.0/dead-code.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/dead-code/0.8.0/dead-code.sol",
"is_dependency": false,
"lines": [
26,
27,
28
],
"starting_column": 5,
"ending_column": 6
},
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "Test4",
"source_mapping": {
"start": 290,
"length": 87,
"filename_used": "/GENERIC_PATH",
"filename_relative": "tests/detectors/dead-code/0.8.0/dead-code.sol",
"filename_absolute": "/GENERIC_PATH",
"filename_short": "tests/detectors/dead-code/0.8.0/dead-code.sol",
"is_dependency": false,
"lines": [
25,
26,
27,
28,
29
],
"starting_column": 1,
"ending_column": 2
}
},
"signature": "unused_but_shadowed()"
}
}
],
"description": "Test4.unused_but_shadowed() (tests/detectors/dead-code/0.8.0/dead-code.sol#26-28) is never used and should be removed\n",
"markdown": "[Test4.unused_but_shadowed()](tests/detectors/dead-code/0.8.0/dead-code.sol#L26-L28) is never used and should be removed\n",
"first_markdown_element": "tests/detectors/dead-code/0.8.0/dead-code.sol#L26-L28",
"id": "74ea8421cf7fa9e04d243014b61f3eee7a9c7648df98316c3881dd4f1f2ab3f7",
"check": "dead-code",
"impact": "Informational",
"confidence": "Medium"
}
]
]
5 changes: 5 additions & 0 deletions tests/test_detectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,11 @@ def id_test(test_item: Test):
"predeclaration_usage_local.sol",
"0.4.25",
),
Test(
all_detectors.DeadCode,
"dead-code.sol",
"0.8.0",
),
]
GENERIC_PATH = "/GENERIC_PATH"

Expand Down

0 comments on commit ffbb62b

Please sign in to comment.