Open source detector for multiple calls in a loop

pull/113/head
Josselin 6 years ago
parent e0a0e9918f
commit 30b0f19c0b
  1. 1
      scripts/tests_generate_expected_json_4.sh
  2. 2
      scripts/travis_test_4.sh
  3. 5
      slither/__main__.py
  4. 76
      slither/detectors/statements/calls_in_loop.py
  5. 1
      tests/expected_json/multiple_calls_in_loop.calls-loop.json
  6. 15
      tests/multiple_calls_in_loop.sol

@ -38,3 +38,4 @@ generate_expected_json tests/unused_return.sol "unused-return"
generate_expected_json tests/shadowing_state_variable.sol "shadowing-state"
generate_expected_json tests/shadowing_abstract.sol "shadowing-abstract"
generate_expected_json tests/timestamp.sol "timestamp"
generate_expected_json tests/multiple_calls_in_loop.sol "calls-loop"

@ -89,6 +89,6 @@ test_slither tests/unused_return.sol "unused-return"
test_slither tests/shadowing_abstract.sol "shadowing-abstract"
test_slither tests/shadowing_state_variable.sol "shadowing-state"
test_slither tests/timestamp.sol "timestamp"
test_slither tests/multiple_calls_in_loop.sol "calls-loop"

@ -130,6 +130,8 @@ def get_detectors_and_printers():
from slither.detectors.shadowing.abstract import ShadowingAbstractDetection
from slither.detectors.shadowing.state import StateShadowing
from slither.detectors.operations.block_timestamp import Timestamp
from slither.detectors.statements.calls_in_loop import MultipleCallsInLoop
detectors = [Backdoor,
UninitializedStateVarsDetection,
@ -154,7 +156,8 @@ def get_detectors_and_printers():
ConstantFunctions,
ShadowingAbstractDetection,
StateShadowing,
Timestamp]
Timestamp,
MultipleCallsInLoop]
from slither.printers.summary.function import FunctionSummary
from slither.printers.summary.contract import ContractSummary

@ -0,0 +1,76 @@
"""
"""
from slither.core.cfg.node import NodeType
from slither.detectors.abstract_detector import (AbstractDetector,
DetectorClassification)
from slither.slithir.operations import (HighLevelCall, LibraryCall,
LowLevelCall, Send, Transfer)
class MultipleCallsInLoop(AbstractDetector):
"""
"""
ARGUMENT = 'calls-loop'
HELP = 'Multiple calls in a loop'
IMPACT = DetectorClassification.LOW
CONFIDENCE = DetectorClassification.MEDIUM
WIKI = 'https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description/_edit#calls-inside-a-loop'
@staticmethod
def call_in_loop(node, in_loop, visited, ret):
if node in visited:
return
# shared visited
visited.append(node)
if node.type == NodeType.STARTLOOP:
in_loop = True
elif node.type == NodeType.ENDLOOP:
in_loop = False
if in_loop:
for ir in node.irs:
if isinstance(ir, (LowLevelCall,
HighLevelCall,
Send,
Transfer)):
if isinstance(ir, LibraryCall):
continue
ret.append(node)
for son in node.sons:
MultipleCallsInLoop.call_in_loop(son, in_loop, visited, ret)
@staticmethod
def detect_call_in_loop(contract):
ret = []
for f in contract.functions + contract.modifiers:
if f.contract == contract and f.is_implemented:
MultipleCallsInLoop.call_in_loop(f.entry_point,
False, [], ret)
return ret
def detect(self):
"""
"""
results = []
for c in self.contracts:
values = self.detect_call_in_loop(c)
for node in values:
func = node.function
info = "{}.{} has external calls inside a loop:\n"
info = info.format(func.contract.name, func.name)
info += "\t- {} ({})\n".format(node.expression, node.source_mapping_str)
self.log(info)
json = self.generate_json_result(info)
self.add_function_to_json(func, json)
self.add_nodes_to_json([node], json)
results.append(json)
return results

@ -0,0 +1 @@
[{"check": "calls-loop", "impact": "Low", "confidence": "Medium", "description": "CallInLoop.bad has external calls inside a loop:\n\t- destinations[i].transfer(i) (tests/multiple_calls_in_loop.sol#11)\n", "elements": [{"type": "function", "name": "bad", "source_mapping": {"start": 153, "length": 135, "filename": "tests/multiple_calls_in_loop.sol", "lines": [9, 10, 11, 12, 13]}, "contract": {"type": "contract", "name": "CallInLoop", "source_mapping": {"start": 0, "length": 291, "filename": "tests/multiple_calls_in_loop.sol", "lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]}}}, {"type": "expression", "expression": "destinations[i].transfer(i)", "source_mapping": {"start": 244, "length": 27, "filename": "tests/multiple_calls_in_loop.sol", "lines": [11]}}]}]

@ -0,0 +1,15 @@
contract CallInLoop{
address[] destinations;
constructor(address[] newDestinations) public{
destinations = newDestinations;
}
function bad() external{
for (uint i=0; i < destinations.length; i++){
destinations[i].transfer(i);
}
}
}
Loading…
Cancel
Save