mirror of https://github.com/crytic/slither
commit
722b9a6867
@ -0,0 +1,68 @@ |
|||||||
|
""" |
||||||
|
Module detecting unused return values from external calls |
||||||
|
""" |
||||||
|
|
||||||
|
from collections import defaultdict |
||||||
|
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification |
||||||
|
from slither.slithir.operations.high_level_call import HighLevelCall |
||||||
|
from slither.core.variables.state_variable import StateVariable |
||||||
|
|
||||||
|
class UnusedReturnValues(AbstractDetector): |
||||||
|
""" |
||||||
|
If the return value of a function is never used, it's likely to be bug |
||||||
|
""" |
||||||
|
|
||||||
|
ARGUMENT = 'unused-return' |
||||||
|
HELP = 'Unused return values' |
||||||
|
IMPACT = DetectorClassification.LOW |
||||||
|
CONFIDENCE = DetectorClassification.MEDIUM |
||||||
|
|
||||||
|
WIKI = 'https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#unused-return' |
||||||
|
|
||||||
|
def detect_unused_return_values(self, f): |
||||||
|
""" |
||||||
|
Return the nodes where the return value of a call is unused |
||||||
|
Args: |
||||||
|
f (Function) |
||||||
|
Returns: |
||||||
|
list(Node) |
||||||
|
""" |
||||||
|
values_returned = [] |
||||||
|
nodes_origin = {} |
||||||
|
for n in f.nodes: |
||||||
|
for ir in n.irs: |
||||||
|
if isinstance(ir, HighLevelCall): |
||||||
|
# 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) |
||||||
|
nodes_origin[ir.lvalue] = ir |
||||||
|
for read in ir.read: |
||||||
|
if read in values_returned: |
||||||
|
values_returned.remove(read) |
||||||
|
|
||||||
|
return [nodes_origin[value].node for value in values_returned] |
||||||
|
|
||||||
|
def detect(self): |
||||||
|
""" Detect unused high level calls that return a value but are never used |
||||||
|
""" |
||||||
|
results = [] |
||||||
|
for c in self.slither.contracts: |
||||||
|
for f in c.functions + c.modifiers: |
||||||
|
unused_return = self.detect_unused_return_values(f) |
||||||
|
if unused_return: |
||||||
|
info = "{}.{} ({}) does not use the value returned by external calls:\n" |
||||||
|
info = info.format(f.contract.name, |
||||||
|
f.name, |
||||||
|
f.source_mapping_str) |
||||||
|
for node in unused_return: |
||||||
|
info += "\t-{} ({})\n".format(node.expression, node.source_mapping_str) |
||||||
|
self.log(info) |
||||||
|
|
||||||
|
sourceMapping = [v.source_mapping for v in unused_return] |
||||||
|
|
||||||
|
results.append({'vuln': 'UnusedReturn', |
||||||
|
'sourceMapping': sourceMapping, |
||||||
|
'filename': self.filename, |
||||||
|
'contract': c.name, |
||||||
|
'expressions':[str(n.expression) for n in unused_return]}) |
||||||
|
return results |
@ -0,0 +1,29 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"contract": "User", |
||||||
|
"expressions": [ |
||||||
|
"a.add(0)", |
||||||
|
"t.f()" |
||||||
|
], |
||||||
|
"filename": "tests/unused_return.sol", |
||||||
|
"sourceMapping": [ |
||||||
|
{ |
||||||
|
"filename": "tests/unused_return.sol", |
||||||
|
"length": 5, |
||||||
|
"lines": [ |
||||||
|
18 |
||||||
|
], |
||||||
|
"start": 263 |
||||||
|
}, |
||||||
|
{ |
||||||
|
"filename": "tests/unused_return.sol", |
||||||
|
"length": 8, |
||||||
|
"lines": [ |
||||||
|
22 |
||||||
|
], |
||||||
|
"start": 337 |
||||||
|
} |
||||||
|
], |
||||||
|
"vuln": "UnusedReturn" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,30 @@ |
|||||||
|
pragma solidity ^0.4.24; |
||||||
|
|
||||||
|
library SafeMath{ |
||||||
|
function add(uint a, uint b) public returns(uint){ |
||||||
|
return a+b; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
contract Target{ |
||||||
|
function f() returns(uint); |
||||||
|
} |
||||||
|
|
||||||
|
contract User{ |
||||||
|
|
||||||
|
using SafeMath for uint; |
||||||
|
|
||||||
|
function test(Target t){ |
||||||
|
t.f(); |
||||||
|
|
||||||
|
// example with library usage |
||||||
|
uint a; |
||||||
|
a.add(0); |
||||||
|
|
||||||
|
// The value is not used |
||||||
|
// But the detector should not detect it |
||||||
|
// As the value returned by the call is stored |
||||||
|
// (unused local variable should be another issue) |
||||||
|
uint b = a.add(1); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue