From 128b0cf5c11482fda10ff8c18df11aa76128d182 Mon Sep 17 00:00:00 2001 From: Natalie Chin Date: Fri, 18 Dec 2020 14:53:24 -0500 Subject: [PATCH 01/35] Added tests for benign reentrancy --- .../reentrancy-benign/reentrancy-benign.sol | 61 + ...cy-benign.sol.0.4.26.ReentrancyBenign.json | 4580 +++++++++++++++++ tests/test_detectors.py | 5 + 3 files changed, 4646 insertions(+) create mode 100644 tests/detectors/reentrancy-benign/reentrancy-benign.sol create mode 100644 tests/detectors/reentrancy-benign/reentrancy-benign.sol.0.4.26.ReentrancyBenign.json diff --git a/tests/detectors/reentrancy-benign/reentrancy-benign.sol b/tests/detectors/reentrancy-benign/reentrancy-benign.sol new file mode 100644 index 000000000..8b37f9852 --- /dev/null +++ b/tests/detectors/reentrancy-benign/reentrancy-benign.sol @@ -0,0 +1,61 @@ +pragma solidity ^0.4.0; + +contract ReentrancyBenign { + uint8 anotherVariableToChange; + uint8 counter = 0; + + function bad0() public { + if (!(msg.sender.call())) { + revert(); + } + counter += 1; + } + + function bad1(address target) public { + (bool success) = target.call(); + require(success); + counter += 1; + } + + function bad2(address target) public { + (bool success) = target.call(); + if (success) { + address(target).call.value(1000)(); + counter += 1; + } + else { + revert(); + } + } + + function bad3(address target) public { + externalCaller(target); + varChanger(); + ethSender(target); + } + + function bad4(address target) public { + externalCaller(target); + ethSender(address(0)); + varChanger(); + address(target).call.value(2)(); + } + + function bad5(address target) public { + ethSender(address(0)); + varChanger(); + ethSender(address(0)); + } + + function externalCaller(address target) private { + address(target).call(); + } + + function ethSender(address target) private { + address(target).call.value(1)(); + } + + function varChanger() private { + anotherVariableToChange++; + } +} \ No newline at end of file diff --git a/tests/detectors/reentrancy-benign/reentrancy-benign.sol.0.4.26.ReentrancyBenign.json b/tests/detectors/reentrancy-benign/reentrancy-benign.sol.0.4.26.ReentrancyBenign.json new file mode 100644 index 000000000..46c1bb4f3 --- /dev/null +++ b/tests/detectors/reentrancy-benign/reentrancy-benign.sol.0.4.26.ReentrancyBenign.json @@ -0,0 +1,4580 @@ +[ + [ + { + "elements": [ + { + "type": "function", + "name": "bad0", + "source_mapping": { + "start": 116, + "length": 120, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 7, + 8, + 9, + 10, + 11, + 12 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad0()" + } + }, + { + "type": "node", + "name": "! (msg.sender.call())", + "source_mapping": { + "start": 153, + "length": 20, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 8 + ], + "starting_column": 13, + "ending_column": 33 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad0", + "source_mapping": { + "start": 116, + "length": 120, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 7, + 8, + 9, + 10, + 11, + 12 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad0()" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls" + } + }, + { + "type": "node", + "name": "! (msg.sender.call())", + "source_mapping": { + "start": 153, + "length": 20, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 8 + ], + "starting_column": 13, + "ending_column": 33 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad0", + "source_mapping": { + "start": 116, + "length": 120, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 7, + 8, + 9, + 10, + 11, + 12 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad0()" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "counter += 1", + "source_mapping": { + "start": 217, + "length": 12, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 11 + ], + "starting_column": 9, + "ending_column": 21 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad0", + "source_mapping": { + "start": 116, + "length": 120, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 7, + 8, + 9, + 10, + 11, + 12 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad0()" + } + } + }, + "additional_fields": { + "underlying_type": "variables_written", + "variable_name": "counter" + } + } + ], + "description": "Reentrancy in ReentrancyBenign.bad0() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#7-12):\n\tExternal calls:\n\t- ! (msg.sender.call()) (tests/detectors/reentrancy-benign/reentrancy-benign.sol#8)\n\tState variables written after the call(s):\n\t- counter += 1 (tests/detectors/reentrancy-benign/reentrancy-benign.sol#11)\n", + "markdown": "Reentrancy in [ReentrancyBenign.bad0()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L7-L12):\n\tExternal calls:\n\t- [! (msg.sender.call())](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L8)\n\tState variables written after the call(s):\n\t- [counter += 1](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L11)\n", + "id": "23f4fbdccaa9fd4c46c12759d22b8f19d92b6652303c84f8a9e59012a83cbf9c", + "check": "reentrancy-benign", + "impact": "Low", + "confidence": "Medium" + }, + { + "elements": [ + { + "type": "function", + "name": "bad1", + "source_mapping": { + "start": 242, + "length": 132, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 14, + 15, + 16, + 17, + 18 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad1(address)" + } + }, + { + "type": "node", + "name": "success = target.call()", + "source_mapping": { + "start": 289, + "length": 30, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 15 + ], + "starting_column": 9, + "ending_column": 39 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad1", + "source_mapping": { + "start": 242, + "length": 132, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 14, + 15, + 16, + 17, + 18 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad1(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls" + } + }, + { + "type": "node", + "name": "success = target.call()", + "source_mapping": { + "start": 289, + "length": 30, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 15 + ], + "starting_column": 9, + "ending_column": 39 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad1", + "source_mapping": { + "start": 242, + "length": 132, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 14, + 15, + 16, + 17, + 18 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad1(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "counter += 1", + "source_mapping": { + "start": 355, + "length": 12, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 17 + ], + "starting_column": 9, + "ending_column": 21 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad1", + "source_mapping": { + "start": 242, + "length": 132, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 14, + 15, + 16, + 17, + 18 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad1(address)" + } + } + }, + "additional_fields": { + "underlying_type": "variables_written", + "variable_name": "counter" + } + } + ], + "description": "Reentrancy in ReentrancyBenign.bad1(address) (tests/detectors/reentrancy-benign/reentrancy-benign.sol#14-18):\n\tExternal calls:\n\t- success = target.call() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#15)\n\tState variables written after the call(s):\n\t- counter += 1 (tests/detectors/reentrancy-benign/reentrancy-benign.sol#17)\n", + "markdown": "Reentrancy in [ReentrancyBenign.bad1(address)](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L14-L18):\n\tExternal calls:\n\t- [success = target.call()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L15)\n\tState variables written after the call(s):\n\t- [counter += 1](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L17)\n", + "id": "404eb3881e9d5765548d023eeacff9a2147786601b5d7eaa204c3838b7d665d9", + "check": "reentrancy-benign", + "impact": "Low", + "confidence": "Medium" + }, + { + "elements": [ + { + "type": "function", + "name": "bad2", + "source_mapping": { + "start": 380, + "length": 238, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad2(address)" + } + }, + { + "type": "node", + "name": "success = target.call()", + "source_mapping": { + "start": 427, + "length": 30, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 21 + ], + "starting_column": 9, + "ending_column": 39 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad2", + "source_mapping": { + "start": 380, + "length": 238, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad2(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls" + } + }, + { + "type": "node", + "name": "address(target).call.value(1000)()", + "source_mapping": { + "start": 494, + "length": 34, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 23 + ], + "starting_column": 13, + "ending_column": 47 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad2", + "source_mapping": { + "start": 380, + "length": 238, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad2(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls" + } + }, + { + "type": "node", + "name": "success = target.call()", + "source_mapping": { + "start": 427, + "length": 30, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 21 + ], + "starting_column": 9, + "ending_column": 39 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad2", + "source_mapping": { + "start": 380, + "length": 238, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad2(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "address(target).call.value(1000)()", + "source_mapping": { + "start": 494, + "length": 34, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 23 + ], + "starting_column": 13, + "ending_column": 47 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad2", + "source_mapping": { + "start": 380, + "length": 238, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad2(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "counter += 1", + "source_mapping": { + "start": 542, + "length": 12, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 24 + ], + "starting_column": 13, + "ending_column": 25 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad2", + "source_mapping": { + "start": 380, + "length": 238, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad2(address)" + } + } + }, + "additional_fields": { + "underlying_type": "variables_written", + "variable_name": "counter" + } + } + ], + "description": "Reentrancy in ReentrancyBenign.bad2(address) (tests/detectors/reentrancy-benign/reentrancy-benign.sol#20-29):\n\tExternal calls:\n\t- success = target.call() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#21)\n\t- address(target).call.value(1000)() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#23)\n\tExternal calls sending eth:\n\t- address(target).call.value(1000)() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#23)\n\tState variables written after the call(s):\n\t- counter += 1 (tests/detectors/reentrancy-benign/reentrancy-benign.sol#24)\n", + "markdown": "Reentrancy in [ReentrancyBenign.bad2(address)](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L20-L29):\n\tExternal calls:\n\t- [success = target.call()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L21)\n\t- [address(target).call.value(1000)()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L23)\n\tExternal calls sending eth:\n\t- [address(target).call.value(1000)()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L23)\n\tState variables written after the call(s):\n\t- [counter += 1](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L24)\n", + "id": "cf749257747679a6caaf9ae293360de238a17a22a13320f189e438e4e226276f", + "check": "reentrancy-benign", + "impact": "Low", + "confidence": "Medium" + }, + { + "elements": [ + { + "type": "function", + "name": "bad3", + "source_mapping": { + "start": 624, + "length": 125, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 31, + 32, + 33, + 34, + 35 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad3(address)" + } + }, + { + "type": "node", + "name": "externalCaller(target)", + "source_mapping": { + "start": 671, + "length": 22, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 32 + ], + "starting_column": 9, + "ending_column": 31 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad3", + "source_mapping": { + "start": 624, + "length": 125, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 31, + 32, + 33, + 34, + 35 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad3(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls" + } + }, + { + "type": "node", + "name": "address(target).call()", + "source_mapping": { + "start": 1123, + "length": 22, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 51 + ], + "starting_column": 9, + "ending_column": 31 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "externalCaller", + "source_mapping": { + "start": 1065, + "length": 87, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 50, + 51, + 52 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "externalCaller(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "externalCaller(target)", + "source_mapping": { + "start": 671, + "length": 22, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 32 + ], + "starting_column": 9, + "ending_column": 31 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad3", + "source_mapping": { + "start": 624, + "length": 125, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 31, + 32, + 33, + 34, + 35 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad3(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "address(target).call()", + "source_mapping": { + "start": 1123, + "length": 22, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 51 + ], + "starting_column": 9, + "ending_column": 31 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "externalCaller", + "source_mapping": { + "start": 1065, + "length": 87, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 50, + 51, + 52 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "externalCaller(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "varChanger()", + "source_mapping": { + "start": 703, + "length": 12, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 33 + ], + "starting_column": 9, + "ending_column": 21 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad3", + "source_mapping": { + "start": 624, + "length": 125, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 31, + 32, + 33, + 34, + 35 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad3(address)" + } + } + }, + "additional_fields": { + "underlying_type": "variables_written", + "variable_name": "anotherVariableToChange" + } + }, + { + "type": "node", + "name": "anotherVariableToChange ++", + "source_mapping": { + "start": 1295, + "length": 25, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 59 + ], + "starting_column": 9, + "ending_column": 34 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "varChanger", + "source_mapping": { + "start": 1255, + "length": 72, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 58, + 59, + 60 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "varChanger()" + } + } + }, + "additional_fields": { + "underlying_type": "variables_written", + "variable_name": "anotherVariableToChange" + } + } + ], + "description": "Reentrancy in ReentrancyBenign.bad3(address) (tests/detectors/reentrancy-benign/reentrancy-benign.sol#31-35):\n\tExternal calls:\n\t- externalCaller(target) (tests/detectors/reentrancy-benign/reentrancy-benign.sol#32)\n\t\t- address(target).call() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#51)\n\tState variables written after the call(s):\n\t- varChanger() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#33)\n\t\t- anotherVariableToChange ++ (tests/detectors/reentrancy-benign/reentrancy-benign.sol#59)\n", + "markdown": "Reentrancy in [ReentrancyBenign.bad3(address)](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L31-L35):\n\tExternal calls:\n\t- [externalCaller(target)](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L32)\n\t\t- [address(target).call()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L51)\n\tState variables written after the call(s):\n\t- [varChanger()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L33)\n\t\t- [anotherVariableToChange ++](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L59)\n", + "id": "5419993a97881c5ada3458672ea5955e9eefae288ac2d4fd84854499ff1569b5", + "check": "reentrancy-benign", + "impact": "Low", + "confidence": "Medium" + }, + { + "elements": [ + { + "type": "function", + "name": "bad4", + "source_mapping": { + "start": 755, + "length": 170, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad4(address)" + } + }, + { + "type": "node", + "name": "externalCaller(target)", + "source_mapping": { + "start": 802, + "length": 22, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 38 + ], + "starting_column": 9, + "ending_column": 31 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad4", + "source_mapping": { + "start": 755, + "length": 170, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad4(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls" + } + }, + { + "type": "node", + "name": "address(target).call()", + "source_mapping": { + "start": 1123, + "length": 22, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 51 + ], + "starting_column": 9, + "ending_column": 31 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "externalCaller", + "source_mapping": { + "start": 1065, + "length": 87, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 50, + 51, + 52 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "externalCaller(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "ethSender(address(0))", + "source_mapping": { + "start": 834, + "length": 21, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 39 + ], + "starting_column": 9, + "ending_column": 30 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad4", + "source_mapping": { + "start": 755, + "length": 170, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad4(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls" + } + }, + { + "type": "node", + "name": "address(target).call.value(1)()", + "source_mapping": { + "start": 1211, + "length": 31, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 55 + ], + "starting_column": 9, + "ending_column": 40 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "ethSender", + "source_mapping": { + "start": 1158, + "length": 91, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 54, + 55, + 56 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "ethSender(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "externalCaller(target)", + "source_mapping": { + "start": 802, + "length": 22, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 38 + ], + "starting_column": 9, + "ending_column": 31 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad4", + "source_mapping": { + "start": 755, + "length": 170, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad4(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "address(target).call()", + "source_mapping": { + "start": 1123, + "length": 22, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 51 + ], + "starting_column": 9, + "ending_column": 31 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "externalCaller", + "source_mapping": { + "start": 1065, + "length": 87, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 50, + 51, + 52 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "externalCaller(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "ethSender(address(0))", + "source_mapping": { + "start": 834, + "length": 21, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 39 + ], + "starting_column": 9, + "ending_column": 30 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad4", + "source_mapping": { + "start": 755, + "length": 170, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad4(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "address(target).call.value(1)()", + "source_mapping": { + "start": 1211, + "length": 31, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 55 + ], + "starting_column": 9, + "ending_column": 40 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "ethSender", + "source_mapping": { + "start": 1158, + "length": 91, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 54, + 55, + 56 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "ethSender(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "varChanger()", + "source_mapping": { + "start": 865, + "length": 12, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 40 + ], + "starting_column": 9, + "ending_column": 21 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad4", + "source_mapping": { + "start": 755, + "length": 170, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad4(address)" + } + } + }, + "additional_fields": { + "underlying_type": "variables_written", + "variable_name": "anotherVariableToChange" + } + }, + { + "type": "node", + "name": "anotherVariableToChange ++", + "source_mapping": { + "start": 1295, + "length": 25, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 59 + ], + "starting_column": 9, + "ending_column": 34 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "varChanger", + "source_mapping": { + "start": 1255, + "length": 72, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 58, + 59, + 60 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "varChanger()" + } + } + }, + "additional_fields": { + "underlying_type": "variables_written", + "variable_name": "anotherVariableToChange" + } + } + ], + "description": "Reentrancy in ReentrancyBenign.bad4(address) (tests/detectors/reentrancy-benign/reentrancy-benign.sol#37-42):\n\tExternal calls:\n\t- externalCaller(target) (tests/detectors/reentrancy-benign/reentrancy-benign.sol#38)\n\t\t- address(target).call() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#51)\n\t- ethSender(address(0)) (tests/detectors/reentrancy-benign/reentrancy-benign.sol#39)\n\t\t- address(target).call.value(1)() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#55)\n\tExternal calls sending eth:\n\t- ethSender(address(0)) (tests/detectors/reentrancy-benign/reentrancy-benign.sol#39)\n\t\t- address(target).call.value(1)() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#55)\n\tState variables written after the call(s):\n\t- varChanger() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#40)\n\t\t- anotherVariableToChange ++ (tests/detectors/reentrancy-benign/reentrancy-benign.sol#59)\n", + "markdown": "Reentrancy in [ReentrancyBenign.bad4(address)](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L37-L42):\n\tExternal calls:\n\t- [externalCaller(target)](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L38)\n\t\t- [address(target).call()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L51)\n\t- [ethSender(address(0))](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L39)\n\t\t- [address(target).call.value(1)()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L55)\n\tExternal calls sending eth:\n\t- [ethSender(address(0))](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L39)\n\t\t- [address(target).call.value(1)()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L55)\n\tState variables written after the call(s):\n\t- [varChanger()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L40)\n\t\t- [anotherVariableToChange ++](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L59)\n", + "id": "fa81e2a2e03ed4653b8e905384a02bfa7fedc6f9dbbcfed919c9c7e7d39958eb", + "check": "reentrancy-benign", + "impact": "Low", + "confidence": "Medium" + }, + { + "elements": [ + { + "type": "function", + "name": "bad5", + "source_mapping": { + "start": 931, + "length": 128, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 44, + 45, + 46, + 47, + 48 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad5(address)" + } + }, + { + "type": "node", + "name": "ethSender(address(0))", + "source_mapping": { + "start": 978, + "length": 21, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 45 + ], + "starting_column": 9, + "ending_column": 30 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad5", + "source_mapping": { + "start": 931, + "length": 128, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 44, + 45, + 46, + 47, + 48 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad5(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls" + } + }, + { + "type": "node", + "name": "address(target).call.value(1)()", + "source_mapping": { + "start": 1211, + "length": 31, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 55 + ], + "starting_column": 9, + "ending_column": 40 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "ethSender", + "source_mapping": { + "start": 1158, + "length": 91, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 54, + 55, + 56 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "ethSender(address)" + } + } + }, + "additional_fields": { + "underlying_type": "external_calls_sending_eth" + } + }, + { + "type": "node", + "name": "varChanger()", + "source_mapping": { + "start": 1009, + "length": 12, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 46 + ], + "starting_column": 9, + "ending_column": 21 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "bad5", + "source_mapping": { + "start": 931, + "length": 128, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 44, + 45, + 46, + 47, + 48 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "bad5(address)" + } + } + }, + "additional_fields": { + "underlying_type": "variables_written", + "variable_name": "anotherVariableToChange" + } + }, + { + "type": "node", + "name": "anotherVariableToChange ++", + "source_mapping": { + "start": 1295, + "length": 25, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 59 + ], + "starting_column": 9, + "ending_column": 34 + }, + "type_specific_fields": { + "parent": { + "type": "function", + "name": "varChanger", + "source_mapping": { + "start": 1255, + "length": 72, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 58, + 59, + 60 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "ReentrancyBenign", + "source_mapping": { + "start": 25, + "length": 1304, + "filename_used": "/GENERIC_PATH", + "filename_relative": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62 + ], + "starting_column": 1, + "ending_column": 0 + } + }, + "signature": "varChanger()" + } + } + }, + "additional_fields": { + "underlying_type": "variables_written", + "variable_name": "anotherVariableToChange" + } + } + ], + "description": "Reentrancy in ReentrancyBenign.bad5(address) (tests/detectors/reentrancy-benign/reentrancy-benign.sol#44-48):\n\tExternal calls:\n\t- ethSender(address(0)) (tests/detectors/reentrancy-benign/reentrancy-benign.sol#45)\n\t\t- address(target).call.value(1)() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#55)\n\tState variables written after the call(s):\n\t- varChanger() (tests/detectors/reentrancy-benign/reentrancy-benign.sol#46)\n\t\t- anotherVariableToChange ++ (tests/detectors/reentrancy-benign/reentrancy-benign.sol#59)\n", + "markdown": "Reentrancy in [ReentrancyBenign.bad5(address)](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L44-L48):\n\tExternal calls:\n\t- [ethSender(address(0))](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L45)\n\t\t- [address(target).call.value(1)()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L55)\n\tState variables written after the call(s):\n\t- [varChanger()](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L46)\n\t\t- [anotherVariableToChange ++](tests/detectors/reentrancy-benign/reentrancy-benign.sol#L59)\n", + "id": "ef84aa3ab4543f3983d06b6aa80c190924de70eb4e679a9a4330efa67f406ae6", + "check": "reentrancy-benign", + "impact": "Low", + "confidence": "Medium" + } + ] +] \ No newline at end of file diff --git a/tests/test_detectors.py b/tests/test_detectors.py index 24c82b9a7..b3bb4a50e 100644 --- a/tests/test_detectors.py +++ b/tests/test_detectors.py @@ -53,6 +53,11 @@ def id_test(test_item: Test): ALL_TESTS = [ + Test( + all_detectors.ReentrancyBenign, + "tests/detectors/reentrancy-benign/reentrancy-benign.sol", + "0.4.26", + ), Test( all_detectors.ReentrancyReadBeforeWritten, "tests/detectors/reentrancy-before-write/reentrancy-write.sol", From 97eb7ec815a04e9b03f9178a21da5993cdab8ee0 Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Tue, 29 Dec 2020 14:52:59 -0600 Subject: [PATCH 02/35] fix that Function.can_send_eth wrongly returns self._can_reenter --- slither/core/declarations/function.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/core/declarations/function.py b/slither/core/declarations/function.py index ff44b0474..195333ca1 100644 --- a/slither/core/declarations/function.py +++ b/slither/core/declarations/function.py @@ -309,7 +309,7 @@ class Function(metaclass=ABCMeta): # pylint: disable=too-many-public-methods if isinstance(ir, Call) and ir.can_send_eth(): self._can_send_eth = True return True - return self._can_reenter + return self._can_send_eth @property def slither(self) -> "SlitherCore": From 9f1a07e36c06f9d3397f5e8f816af61e605eeea5 Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Wed, 30 Dec 2020 14:25:12 -0600 Subject: [PATCH 03/35] introduce tests for slither.core.declarations.Function --- tests/test_function.py | 83 +++++++++++++++++++++++++++++++++++++++++ tests/test_function.sol | 39 +++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 tests/test_function.py create mode 100644 tests/test_function.sol diff --git a/tests/test_function.py b/tests/test_function.py new file mode 100644 index 000000000..37df7380a --- /dev/null +++ b/tests/test_function.py @@ -0,0 +1,83 @@ +from slither import Slither +from slither.core.declarations.function import FunctionType +from slither.core.solidity_types.elementary_type import ElementaryType + +""" +tests for slither.core.declarations.Function. +tests that `tests/functions.sol` gets translated into correct +slither.core.declarations.Function objects or its subclasses +and that these objects behave correctly. +""" + +def test_functions(): + slither = Slither("tests/test_function.sol") + functions = slither.contracts_as_dict["TestFunction"].available_functions_as_dict() + print(functions) + + f = functions["external_payable(uint256)"] + assert f.name == "external_payable" + assert f.full_name == "external_payable(uint256)" + assert f.canonical_name == "TestFunction.external_payable(uint256)" + assert f.solidity_signature == "external_payable(uint256)" + assert f.signature_str == "external_payable(uint256) returns(uint256)" + assert f.function_type == FunctionType.NORMAL + assert not f.contains_assembly + assert not f.can_reenter() + assert not f.can_send_eth() + assert not f.is_constructor + assert not f.is_fallback + assert not f.is_receive + assert f.payable + assert f.visibility == "external" + assert not f.view + assert not f.pure + assert f.is_implemented + assert not f.is_empty + assert f.parameters[0].name == "_a" + assert f.parameters[0].type == ElementaryType("uint256") + assert f.return_type[0] == ElementaryType("uint256") + + f = functions["public_reenter()"] + assert f.name == "public_reenter" + assert f.full_name == "public_reenter()" + assert f.canonical_name == "TestFunction.public_reenter()" + assert f.solidity_signature == "public_reenter()" + assert f.signature_str == "public_reenter() returns()" + assert f.function_type == FunctionType.NORMAL + assert not f.contains_assembly + assert f.can_reenter() + assert not f.can_send_eth() + assert not f.is_constructor + assert not f.is_fallback + assert not f.is_receive + assert not f.payable + assert f.visibility == "public" + assert not f.view + assert not f.pure + assert f.is_implemented + assert not f.is_empty + assert not f.parameters + assert not f.return_type + + f = functions["public_payable_reenter_send(bool)"] + assert f.name == "public_payable_reenter_send" + assert f.full_name == "public_payable_reenter_send(bool)" + assert f.canonical_name == "TestFunction.public_payable_reenter_send(bool)" + assert f.solidity_signature == "public_payable_reenter_send(bool)" + assert f.signature_str == "public_payable_reenter_send(bool) returns()" + assert f.function_type == FunctionType.NORMAL + assert not f.contains_assembly + assert f.can_reenter() + assert f.can_send_eth() + assert not f.is_constructor + assert not f.is_fallback + assert not f.is_receive + assert f.payable + assert f.visibility == "public" + assert not f.view + assert not f.pure + assert f.is_implemented + assert not f.is_empty + assert f.parameters[0].name == "_b" + assert f.parameters[0].type == ElementaryType("bool") + assert not f.return_type diff --git a/tests/test_function.sol b/tests/test_function.sol new file mode 100644 index 000000000..4e26ae999 --- /dev/null +++ b/tests/test_function.sol @@ -0,0 +1,39 @@ +pragma solidity ^0.6.12; + +// solidity source used by tests/test_function.py. +// tests/test_function.py tests that the functions +// below get + +contract TestFunction { + bool entered = false; + + function external_payable(uint _a) external payable returns (uint) { + return 1; + } + + function public_reenter() public { + msg.sender.call(""); + } + + function public_payable_reenter_send(bool _b) public payable { + msg.sender.call{value: 1}(""); + } + + function external_send(uint _a) external { + require(!entered); + entered = true; + msg.sender.call{value: 1}(""); + } + + function _internal(uint _a) internal returns (uint) { + uint256 chain; + assembly { + chain := chainid() + } + return chain; + } + + fallback() external { + + } +} From 78fb96c8a5b7e265073901e8ed6a7114fcf1df0b Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Wed, 30 Dec 2020 14:26:40 -0600 Subject: [PATCH 04/35] test_function.py: fix docstring --- tests/test_function.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_function.py b/tests/test_function.py index 37df7380a..70ddc2815 100644 --- a/tests/test_function.py +++ b/tests/test_function.py @@ -3,9 +3,9 @@ from slither.core.declarations.function import FunctionType from slither.core.solidity_types.elementary_type import ElementaryType """ -tests for slither.core.declarations.Function. -tests that `tests/functions.sol` gets translated into correct -slither.core.declarations.Function objects or its subclasses +tests for `slither.core.declarations.Function`. +tests that `tests/test_function.sol` gets translated into correct +`slither.core.declarations.Function` objects or its subclasses and that these objects behave correctly. """ From 61f71293b035bec481655cb08c8f473210a7ea6e Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Wed, 30 Dec 2020 15:17:28 -0600 Subject: [PATCH 05/35] more tests for slither.core.declarations.Function --- tests/test_function.py | 69 ++++++++++++++++++++++++++++++++++++++++- tests/test_function.sol | 25 ++++++++++++--- 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/tests/test_function.py b/tests/test_function.py index 70ddc2815..ffac27adb 100644 --- a/tests/test_function.py +++ b/tests/test_function.py @@ -12,7 +12,6 @@ and that these objects behave correctly. def test_functions(): slither = Slither("tests/test_function.sol") functions = slither.contracts_as_dict["TestFunction"].available_functions_as_dict() - print(functions) f = functions["external_payable(uint256)"] assert f.name == "external_payable" @@ -81,3 +80,71 @@ def test_functions(): assert f.parameters[0].name == "_b" assert f.parameters[0].type == ElementaryType("bool") assert not f.return_type + + f = functions["external_send(uint8)"] + assert f.name == "external_send" + assert f.full_name == "external_send(uint8)" + assert f.canonical_name == "TestFunction.external_send(uint8)" + assert f.solidity_signature == "external_send(uint8)" + assert f.signature_str == "external_send(uint8) returns()" + assert f.function_type == FunctionType.NORMAL + assert not f.contains_assembly + assert f.can_reenter() + assert f.can_send_eth() + assert not f.is_constructor + assert not f.is_fallback + assert not f.is_receive + assert not f.payable + assert f.visibility == "external" + assert not f.view + assert not f.pure + assert f.is_implemented + assert not f.is_empty + assert f.parameters[0].name == "_c" + assert f.parameters[0].type == ElementaryType("uint8") + assert not f.return_type + + f = functions["internal_assembly(bytes)"] + assert f.name == "internal_assembly" + assert f.full_name == "internal_assembly(bytes)" + assert f.canonical_name == "TestFunction.internal_assembly(bytes)" + assert f.solidity_signature == "internal_assembly(bytes)" + assert f.signature_str == "internal_assembly(bytes) returns(uint256)" + assert f.function_type == FunctionType.NORMAL + assert f.contains_assembly + assert not f.can_reenter() + assert not f.can_send_eth() + assert not f.is_constructor + assert not f.is_fallback + assert not f.is_receive + assert not f.payable + assert f.visibility == "internal" + assert not f.view + assert not f.pure + assert f.is_implemented + assert not f.is_empty + assert f.parameters[0].name == "_d" + assert f.parameters[0].type == ElementaryType("bytes") + assert f.return_type[0] == ElementaryType("uint256") + + f = functions["fallback()"] + assert f.name == "fallback" + assert f.full_name == "fallback()" + assert f.canonical_name == "TestFunction.fallback()" + assert f.solidity_signature == "fallback()" + assert f.signature_str == "fallback() returns()" + assert f.function_type == FunctionType.FALLBACK + assert not f.contains_assembly + assert not f.can_reenter() + assert not f.can_send_eth() + assert not f.is_constructor + assert f.is_fallback + assert not f.is_receive + assert not f.payable + assert f.visibility == "external" + assert not f.view + assert not f.pure + assert f.is_implemented + assert f.is_empty + assert not f.parameters + assert not f.return_type diff --git a/tests/test_function.sol b/tests/test_function.sol index 4e26ae999..c070184ed 100644 --- a/tests/test_function.sol +++ b/tests/test_function.sol @@ -1,8 +1,9 @@ pragma solidity ^0.6.12; // solidity source used by tests/test_function.py. -// tests/test_function.py tests that the functions -// below get +// tests/test_function.py tests that the functions below get translated into correct +// `slither.core.declarations.Function` objects or its subclasses +// and that these objects behave correctly. contract TestFunction { bool entered = false; @@ -19,13 +20,13 @@ contract TestFunction { msg.sender.call{value: 1}(""); } - function external_send(uint _a) external { + function external_send(uint8 _c) external { require(!entered); entered = true; msg.sender.call{value: 1}(""); } - function _internal(uint _a) internal returns (uint) { + function internal_assembly(bytes calldata _d) internal returns (uint) { uint256 chain; assembly { chain := chainid() @@ -36,4 +37,20 @@ contract TestFunction { fallback() external { } + + receive() external payable { + + } + + constructor() public payable { + + } + + function private_view() private view returns (bool) { + return entered; + } + + function public_pure() public pure returns (bool) { + return true; + } } From 9ed760c04ad9bb8cad9d44febab9e50e455c0ffb Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Wed, 30 Dec 2020 19:16:43 -0600 Subject: [PATCH 06/35] black --- tests/test_function.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_function.py b/tests/test_function.py index ffac27adb..6a865e3b3 100644 --- a/tests/test_function.py +++ b/tests/test_function.py @@ -9,6 +9,7 @@ tests that `tests/test_function.sol` gets translated into correct and that these objects behave correctly. """ + def test_functions(): slither = Slither("tests/test_function.sol") functions = slither.contracts_as_dict["TestFunction"].available_functions_as_dict() From 56cc0420314cd719b46deacc559f6e7750a7b1c9 Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Wed, 30 Dec 2020 19:44:07 -0600 Subject: [PATCH 07/35] tests/test_function.py: pass pylint --- tests/test_function.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test_function.py b/tests/test_function.py index 6a865e3b3..42d2e9e56 100644 --- a/tests/test_function.py +++ b/tests/test_function.py @@ -1,7 +1,3 @@ -from slither import Slither -from slither.core.declarations.function import FunctionType -from slither.core.solidity_types.elementary_type import ElementaryType - """ tests for `slither.core.declarations.Function`. tests that `tests/test_function.sol` gets translated into correct @@ -9,8 +5,13 @@ tests that `tests/test_function.sol` gets translated into correct and that these objects behave correctly. """ +from slither import Slither +from slither.core.declarations.function import FunctionType +from slither.core.solidity_types.elementary_type import ElementaryType + def test_functions(): + # pylint: disable=too-many-statements slither = Slither("tests/test_function.sol") functions = slither.contracts_as_dict["TestFunction"].available_functions_as_dict() From 7f87546dd9ab397f8b4af46cb636676691868be5 Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Wed, 30 Dec 2020 19:45:02 -0600 Subject: [PATCH 08/35] fix pylint `No such file or directory: 'tests/__init__.py'` --- tests/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/__init__.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb From 885287348e089d579777b23e3a995cd41bb1b061 Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Wed, 30 Dec 2020 19:45:21 -0600 Subject: [PATCH 09/35] CONTRIBUTING.md: instructions to run black/pylint on tests as well since github superlinter does so and fails otherwise --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6214f80de..07e3976e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,10 +32,10 @@ To run the unit tests, you need Several linters and security checkers are run on the PRs. -To run them locally: +To run them locally in the root dir of the repository: -- `pylint slither --rconfig pyproject.toml` -- `black slither --config pyproject.toml` +- `pylint slither tests --rcfile pyproject.toml` +- `black . --config pyproject.toml` We use black `19.10b0`. ### Detectors tests From 8269561f56584f135db05cd3c0954d648a604b61 Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Wed, 30 Dec 2020 21:30:18 -0600 Subject: [PATCH 10/35] test_function.py: finish for most of the codomain of properties and getters under test --- tests/test_function.py | 89 +++++++++++++++++++++++++++++++++++++++++ tests/test_function.sol | 2 +- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/tests/test_function.py b/tests/test_function.py index 42d2e9e56..9ab16a10d 100644 --- a/tests/test_function.py +++ b/tests/test_function.py @@ -150,3 +150,92 @@ def test_functions(): assert f.is_empty assert not f.parameters assert not f.return_type + + f = functions["receive()"] + assert f.name == "receive" + assert f.full_name == "receive()" + assert f.canonical_name == "TestFunction.receive()" + assert f.solidity_signature == "receive()" + assert f.signature_str == "receive() returns()" + assert f.function_type == FunctionType.RECEIVE + assert not f.contains_assembly + assert not f.can_reenter() + assert not f.can_send_eth() + assert not f.is_constructor + assert not f.is_fallback + assert f.is_receive + assert f.payable + assert f.visibility == "external" + assert not f.view + assert not f.pure + assert f.is_implemented + assert f.is_empty + assert not f.parameters + assert not f.return_type + + f = functions["constructor(address)"] + assert f.name == "constructor" + assert f.full_name == "constructor(address)" + assert f.canonical_name == "TestFunction.constructor(address)" + assert f.solidity_signature == "constructor(address)" + assert f.signature_str == "constructor(address) returns()" + assert f.function_type == FunctionType.CONSTRUCTOR + assert not f.contains_assembly + assert not f.can_reenter() + assert not f.can_send_eth() + assert f.is_constructor + assert not f.is_fallback + assert not f.is_receive + assert f.payable + assert f.visibility == "public" + assert not f.view + assert not f.pure + assert f.is_implemented + assert f.is_empty + assert f.parameters[0].name == "_e" + assert f.parameters[0].type == ElementaryType("address") + assert not f.return_type + + f = functions["private_view()"] + assert f.name == "private_view" + assert f.full_name == "private_view()" + assert f.canonical_name == "TestFunction.private_view()" + assert f.solidity_signature == "private_view()" + assert f.signature_str == "private_view() returns(bool)" + assert f.function_type == FunctionType.NORMAL + assert not f.contains_assembly + assert not f.can_reenter() + assert not f.can_send_eth() + assert not f.is_constructor + assert not f.is_fallback + assert not f.is_receive + assert not f.payable + assert f.visibility == "private" + assert f.view + assert not f.pure + assert f.is_implemented + assert not f.is_empty + assert not f.parameters + assert f.return_type[0] == ElementaryType("bool") + + f = functions["public_pure()"] + assert f.name == "public_pure" + assert f.full_name == "public_pure()" + assert f.canonical_name == "TestFunction.public_pure()" + assert f.solidity_signature == "public_pure()" + assert f.signature_str == "public_pure() returns(bool)" + assert f.function_type == FunctionType.NORMAL + assert not f.contains_assembly + assert not f.can_reenter() + assert not f.can_send_eth() + assert not f.is_constructor + assert not f.is_fallback + assert not f.is_receive + assert not f.payable + assert f.visibility == "public" + assert f.view + assert f.pure + assert f.is_implemented + assert not f.is_empty + assert not f.parameters + assert f.return_type[0] == ElementaryType("bool") diff --git a/tests/test_function.sol b/tests/test_function.sol index c070184ed..43345c51d 100644 --- a/tests/test_function.sol +++ b/tests/test_function.sol @@ -42,7 +42,7 @@ contract TestFunction { } - constructor() public payable { + constructor(address payable _e) public payable { } From b5978e83b3e15b20d61b2fb0f6858f9a6b51dfb1 Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Mon, 4 Jan 2021 17:33:43 -0600 Subject: [PATCH 11/35] stricter assertions that expose that Function.can_send_eth() sometimes returns None instead of bool --- tests/test_function.py | 240 ++++++++++++++++++++--------------------- 1 file changed, 120 insertions(+), 120 deletions(-) diff --git a/tests/test_function.py b/tests/test_function.py index 9ab16a10d..f179c4d8a 100644 --- a/tests/test_function.py +++ b/tests/test_function.py @@ -22,18 +22,18 @@ def test_functions(): assert f.solidity_signature == "external_payable(uint256)" assert f.signature_str == "external_payable(uint256) returns(uint256)" assert f.function_type == FunctionType.NORMAL - assert not f.contains_assembly - assert not f.can_reenter() - assert not f.can_send_eth() - assert not f.is_constructor - assert not f.is_fallback - assert not f.is_receive - assert f.payable + assert f.contains_assembly is False + assert f.can_reenter() is False + assert f.can_send_eth() is False + assert f.is_constructor is False + assert f.is_fallback is False + assert f.is_receive is False + assert f.payable is True assert f.visibility == "external" - assert not f.view - assert not f.pure - assert f.is_implemented - assert not f.is_empty + assert f.view is False + assert f.pure is False + assert f.is_implemented is True + assert f.is_empty is False assert f.parameters[0].name == "_a" assert f.parameters[0].type == ElementaryType("uint256") assert f.return_type[0] == ElementaryType("uint256") @@ -45,20 +45,20 @@ def test_functions(): assert f.solidity_signature == "public_reenter()" assert f.signature_str == "public_reenter() returns()" assert f.function_type == FunctionType.NORMAL - assert not f.contains_assembly - assert f.can_reenter() - assert not f.can_send_eth() - assert not f.is_constructor - assert not f.is_fallback - assert not f.is_receive - assert not f.payable + assert f.contains_assembly is False + assert f.can_reenter() is True + assert f.can_send_eth() is False + assert f.is_constructor is False + assert f.is_fallback is False + assert f.is_receive is False + assert f.payable is False assert f.visibility == "public" - assert not f.view - assert not f.pure - assert f.is_implemented - assert not f.is_empty - assert not f.parameters - assert not f.return_type + assert f.view is False + assert f.pure is False + assert f.is_implemented is True + assert f.is_empty is False + assert f.parameters == [] + assert f.return_type is None f = functions["public_payable_reenter_send(bool)"] assert f.name == "public_payable_reenter_send" @@ -67,21 +67,21 @@ def test_functions(): assert f.solidity_signature == "public_payable_reenter_send(bool)" assert f.signature_str == "public_payable_reenter_send(bool) returns()" assert f.function_type == FunctionType.NORMAL - assert not f.contains_assembly - assert f.can_reenter() - assert f.can_send_eth() - assert not f.is_constructor - assert not f.is_fallback - assert not f.is_receive - assert f.payable + assert f.contains_assembly is False + assert f.can_reenter() is True + assert f.can_send_eth() is True + assert f.is_constructor is False + assert f.is_fallback is False + assert f.is_receive is False + assert f.payable is True assert f.visibility == "public" - assert not f.view - assert not f.pure - assert f.is_implemented - assert not f.is_empty + assert f.view is False + assert f.pure is False + assert f.is_implemented is True + assert f.is_empty is False assert f.parameters[0].name == "_b" assert f.parameters[0].type == ElementaryType("bool") - assert not f.return_type + assert f.return_type is None f = functions["external_send(uint8)"] assert f.name == "external_send" @@ -90,21 +90,21 @@ def test_functions(): assert f.solidity_signature == "external_send(uint8)" assert f.signature_str == "external_send(uint8) returns()" assert f.function_type == FunctionType.NORMAL - assert not f.contains_assembly - assert f.can_reenter() - assert f.can_send_eth() - assert not f.is_constructor - assert not f.is_fallback - assert not f.is_receive - assert not f.payable + assert f.contains_assembly is False + assert f.can_reenter() is True + assert f.can_send_eth() is True + assert f.is_constructor is False + assert f.is_fallback is False + assert f.is_receive is False + assert f.payable is False assert f.visibility == "external" - assert not f.view - assert not f.pure - assert f.is_implemented - assert not f.is_empty + assert f.view is False + assert f.pure is False + assert f.is_implemented is True + assert f.is_empty is False assert f.parameters[0].name == "_c" assert f.parameters[0].type == ElementaryType("uint8") - assert not f.return_type + assert f.return_type is None f = functions["internal_assembly(bytes)"] assert f.name == "internal_assembly" @@ -113,18 +113,18 @@ def test_functions(): assert f.solidity_signature == "internal_assembly(bytes)" assert f.signature_str == "internal_assembly(bytes) returns(uint256)" assert f.function_type == FunctionType.NORMAL - assert f.contains_assembly - assert not f.can_reenter() - assert not f.can_send_eth() - assert not f.is_constructor - assert not f.is_fallback - assert not f.is_receive - assert not f.payable + assert f.contains_assembly is True + assert f.can_reenter() is False + assert f.can_send_eth() is False + assert f.is_constructor is False + assert f.is_fallback is False + assert f.is_receive is False + assert f.payable is False assert f.visibility == "internal" - assert not f.view - assert not f.pure - assert f.is_implemented - assert not f.is_empty + assert f.view is False + assert f.pure is False + assert f.is_implemented is True + assert f.is_empty is False assert f.parameters[0].name == "_d" assert f.parameters[0].type == ElementaryType("bytes") assert f.return_type[0] == ElementaryType("uint256") @@ -136,20 +136,20 @@ def test_functions(): assert f.solidity_signature == "fallback()" assert f.signature_str == "fallback() returns()" assert f.function_type == FunctionType.FALLBACK - assert not f.contains_assembly - assert not f.can_reenter() - assert not f.can_send_eth() - assert not f.is_constructor - assert f.is_fallback - assert not f.is_receive - assert not f.payable + assert f.contains_assembly is False + assert f.can_reenter() is False + assert f.can_send_eth() is False + assert f.is_constructor is False + assert f.is_fallback is True + assert f.is_receive is False + assert f.payable is False assert f.visibility == "external" - assert not f.view - assert not f.pure - assert f.is_implemented - assert f.is_empty - assert not f.parameters - assert not f.return_type + assert f.view is False + assert f.pure is False + assert f.is_implemented is True + assert f.is_empty is True + assert f.parameters == [] + assert f.return_type is None f = functions["receive()"] assert f.name == "receive" @@ -158,20 +158,20 @@ def test_functions(): assert f.solidity_signature == "receive()" assert f.signature_str == "receive() returns()" assert f.function_type == FunctionType.RECEIVE - assert not f.contains_assembly - assert not f.can_reenter() - assert not f.can_send_eth() - assert not f.is_constructor - assert not f.is_fallback - assert f.is_receive - assert f.payable + assert f.contains_assembly is False + assert f.can_reenter() is False + assert f.can_send_eth() is False + assert f.is_constructor is False + assert f.is_fallback is False + assert f.is_receive is True + assert f.payable is True assert f.visibility == "external" - assert not f.view - assert not f.pure - assert f.is_implemented - assert f.is_empty - assert not f.parameters - assert not f.return_type + assert f.view is False + assert f.pure is False + assert f.is_implemented is True + assert f.is_empty is True + assert f.parameters == [] + assert f.return_type is None f = functions["constructor(address)"] assert f.name == "constructor" @@ -180,21 +180,21 @@ def test_functions(): assert f.solidity_signature == "constructor(address)" assert f.signature_str == "constructor(address) returns()" assert f.function_type == FunctionType.CONSTRUCTOR - assert not f.contains_assembly - assert not f.can_reenter() - assert not f.can_send_eth() + assert f.contains_assembly is False + assert f.can_reenter() is False + assert f.can_send_eth() is False assert f.is_constructor - assert not f.is_fallback - assert not f.is_receive - assert f.payable + assert f.is_fallback is False + assert f.is_receive is False + assert f.payable is True assert f.visibility == "public" - assert not f.view - assert not f.pure - assert f.is_implemented - assert f.is_empty + assert f.view is False + assert f.pure is False + assert f.is_implemented is True + assert f.is_empty is True assert f.parameters[0].name == "_e" assert f.parameters[0].type == ElementaryType("address") - assert not f.return_type + assert f.return_type is None f = functions["private_view()"] assert f.name == "private_view" @@ -203,19 +203,19 @@ def test_functions(): assert f.solidity_signature == "private_view()" assert f.signature_str == "private_view() returns(bool)" assert f.function_type == FunctionType.NORMAL - assert not f.contains_assembly - assert not f.can_reenter() - assert not f.can_send_eth() - assert not f.is_constructor - assert not f.is_fallback - assert not f.is_receive - assert not f.payable + assert f.contains_assembly is False + assert f.can_reenter() is False + assert f.can_send_eth() is False + assert f.is_constructor is False + assert f.is_fallback is False + assert f.is_receive is False + assert f.payable is False assert f.visibility == "private" - assert f.view - assert not f.pure - assert f.is_implemented - assert not f.is_empty - assert not f.parameters + assert f.view is True + assert f.pure is False + assert f.is_implemented is True + assert f.is_empty is False + assert f.parameters == [] assert f.return_type[0] == ElementaryType("bool") f = functions["public_pure()"] @@ -225,17 +225,17 @@ def test_functions(): assert f.solidity_signature == "public_pure()" assert f.signature_str == "public_pure() returns(bool)" assert f.function_type == FunctionType.NORMAL - assert not f.contains_assembly - assert not f.can_reenter() - assert not f.can_send_eth() - assert not f.is_constructor - assert not f.is_fallback - assert not f.is_receive - assert not f.payable + assert f.contains_assembly is False + assert f.can_reenter() is False + assert f.can_send_eth() is False + assert f.is_constructor is False + assert f.is_fallback is False + assert f.is_receive is False + assert f.payable is False assert f.visibility == "public" - assert f.view - assert f.pure - assert f.is_implemented - assert not f.is_empty - assert not f.parameters + assert f.view is True + assert f.pure is True + assert f.is_implemented is True + assert f.is_empty is False + assert f.parameters == [] assert f.return_type[0] == ElementaryType("bool") From 05747d6c75a0caeee3ffd08a180dc257c6f658e6 Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Mon, 4 Jan 2021 17:37:16 -0600 Subject: [PATCH 12/35] fix that Function.can_send_eth() sometimes returns None when it's supposed to return bool --- slither/core/declarations/function.py | 1 + 1 file changed, 1 insertion(+) diff --git a/slither/core/declarations/function.py b/slither/core/declarations/function.py index 195333ca1..824c28c19 100644 --- a/slither/core/declarations/function.py +++ b/slither/core/declarations/function.py @@ -305,6 +305,7 @@ class Function(metaclass=ABCMeta): # pylint: disable=too-many-public-methods from slither.slithir.operations import Call if self._can_send_eth is None: + self._can_send_eth = False for ir in self.all_slithir_operations(): if isinstance(ir, Call) and ir.can_send_eth(): self._can_send_eth = True From 00e5d05611ce75f6de1fe3a2187ab0ff08e5c03b Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Tue, 5 Jan 2021 21:14:44 -0600 Subject: [PATCH 13/35] remove duplicate import --- slither/core/declarations/function.py | 1 - 1 file changed, 1 deletion(-) diff --git a/slither/core/declarations/function.py b/slither/core/declarations/function.py index 824c28c19..a7b5669d5 100644 --- a/slither/core/declarations/function.py +++ b/slither/core/declarations/function.py @@ -43,7 +43,6 @@ if TYPE_CHECKING: from slither.core.expressions.expression import Expression from slither.slithir.operations import Operation from slither.slither import Slither - from slither.core.cfg.node import NodeType from slither.core.slither_core import SlitherCore LOGGER = logging.getLogger("Function") From 90b2df1b662fcf639e9c36863b57da6027b4bfc6 Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Tue, 5 Jan 2021 21:15:43 -0600 Subject: [PATCH 14/35] improve docstring of Function.can_send_eth --- slither/core/declarations/function.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/core/declarations/function.py b/slither/core/declarations/function.py index a7b5669d5..3f2e64dbb 100644 --- a/slither/core/declarations/function.py +++ b/slither/core/declarations/function.py @@ -298,7 +298,7 @@ class Function(metaclass=ABCMeta): # pylint: disable=too-many-public-methods def can_send_eth(self) -> bool: """ - Check if the function can send eth + Check if the function or any internal (not external) functions called by it can send eth :return bool: """ from slither.slithir.operations import Call From eb4363a172e72fb850dcf42703aad42190ef49dc Mon Sep 17 00:00:00 2001 From: Maximilian Krueger Date: Tue, 5 Jan 2021 21:16:41 -0600 Subject: [PATCH 15/35] add more tests for Function.can_send_eth --- tests/test_function.py | 20 +++++++++++ tests/test_function.sol | 73 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/tests/test_function.py b/tests/test_function.py index f179c4d8a..273a9eab0 100644 --- a/tests/test_function.py +++ b/tests/test_function.py @@ -239,3 +239,23 @@ def test_functions(): assert f.is_empty is False assert f.parameters == [] assert f.return_type[0] == ElementaryType("bool") + + +def test_function_can_send_eth(): + slither = Slither("tests/test_function.sol") + functions = slither.contracts_as_dict["TestFunctionCanSendEth"].available_functions_as_dict() + + assert functions["send_direct()"].can_send_eth() is True + assert functions["transfer_direct()"].can_send_eth() is True + assert functions["call_direct()"].can_send_eth() is True + assert functions["highlevel_call_direct()"].can_send_eth() is True + + assert functions["send_via_internal()"].can_send_eth() is True + assert functions["transfer_via_internal()"].can_send_eth() is True + assert functions["call_via_internal()"].can_send_eth() is True + assert functions["highlevel_call_via_internal()"].can_send_eth() is True + + assert functions["send_via_external()"].can_send_eth() is False + assert functions["transfer_via_external()"].can_send_eth() is False + assert functions["call_via_external()"].can_send_eth() is False + assert functions["highlevel_call_via_external()"].can_send_eth() is False diff --git a/tests/test_function.sol b/tests/test_function.sol index 43345c51d..6ea6b9d8a 100644 --- a/tests/test_function.sol +++ b/tests/test_function.sol @@ -54,3 +54,76 @@ contract TestFunction { return true; } } + +contract TestFunctionCanSendEth { + + function send_direct() internal { + address(1).send(1); + } + + function transfer_direct() internal { + address(1).transfer(1); + } + + function call_direct() internal { + address(1).call{value: 1}(""); + } + + function highlevel_call_direct() internal { + TestFunctionCanSendEthOther(address(5)).i_am_payable{value: 1}(); + } + + function send_via_internal() public { + send_direct(); + } + + function transfer_via_internal() public { + transfer_direct(); + } + + function call_via_internal() public { + call_direct(); + } + + function highlevel_call_via_internal() public { + highlevel_call_direct(); + } + + function send_via_external() public { + TestFunctionCanSendEthOther(address(5)).send_direct(); + } + + function transfer_via_external() public { + TestFunctionCanSendEthOther(address(5)).transfer_direct(); + } + + function call_via_external() public { + TestFunctionCanSendEthOther(address(5)).call_direct(); + } + + function highlevel_call_via_external() public { + TestFunctionCanSendEthOther(address(5)).highlevel_call_direct(); + } +} + +contract TestFunctionCanSendEthOther { + function i_am_payable() external payable { + + } + + function send_direct() external { + address(1).send(1); + } + + function transfer_direct() external { + address(1).transfer(1); + } + + function call_direct() external { + address(1).call{value: 1}(""); + } + + function highlevel_call_direct() external { + TestFunctionCanSendEthOther(address(5)).i_am_payable{value: 1}(); + } +} From 12c581498f09156b1a72ac01b46fa2d4a7f85cb6 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Mon, 11 Jan 2021 11:27:44 +0100 Subject: [PATCH 16/35] Create trophies.md --- trophies.md | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 trophies.md diff --git a/trophies.md b/trophies.md new file mode 100644 index 000000000..58899bbc8 --- /dev/null +++ b/trophies.md @@ -0,0 +1,83 @@ +# Slither Trophies +The following lists security vulnerabilities that were found by Slither. If you found a security vulnerability using Slither, please submit a PR with the relevant information. + + +## October 2018 +- [Basis](https://github.com/trailofbits/publications/blob/master/reviews/basis.pdf) + - Missing return value check +## November 2018 +- [Origin protocol](https://github.com/trailofbits/publications/blob/master/reviews/origin.pdf) + - Reentrancy +## July 2019 +- [Numerai](https://github.com/trailofbits/publications/blob/master/reviews/numerai.pdf) + - Deletion of a mapping with structure + - Missing return value +## September 2019 +- [Flexa](https://github.com/trailofbits/publications/blob/master/reviews/Flexa.pdf) + - Reentrancy (events out of order) +## October 2019 +- [0x](https://github.com/trailofbits/publications/blob/master/reviews/0x-protocol.pdf) + - Missing return value +## December 2019 +- [Token mint](https://certificate.quantstamp.com/full/token-mint) + - Reentrancies +## February 2020 +- [Airswap](https://certificate.quantstamp.com/full/airswap) + - Missing return value check +## March 202 +- [Stake Technologies Lockdrop](https://certificate.quantstamp.com/full/stake-technologies-lockdrop) + - Dangerous strict equality +## May 2020 +- [E&Y’s Nightfall](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) + - Missing return value + - Empty return value +- [DefiStrategies](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) + - Modifier can return the default value + - Dangerous strict equality allows the contract to be trapped +- [DOSnetwork](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) + - Abi `encodedPacked `collision +- [EthKids](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) + - `msg.value` is used two times to compute a price +- [HQ20](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) + - Reentrancy +## June 2020 +- [88mph](https://certificate.quantstamp.com/full/88-mph) + - Dangerous `block.timestamp` usage +- [Dloop](https://certificate.quantstamp.com/full/dloop-art-registry-smart-contract) + - Dangerous `block.timestamp` usage +## July 2020 +- [Atomic Loans](https://certificate.quantstamp.com/full/atomic-loans) + - Uninitialized state variable + - State variable shadowing + - Reentrancy +- [Parity](https://github.com/trailofbits/publications/blob/master/reviews/parity.pdf) + - Incorrect constructor name + - Deletion of a mapping with structure + - Uninitialized state variables +## August 3 2020 +- [Amp](https://github.com/trailofbits/publications/blob/master/reviews/amp.pdf) + - Duplicate contract name +- [PerlinXRewards](https://certificate.quantstamp.com/full/perlin-x-rewards-sol) + - Multiple reentrancies +## November 2020 +- [Linkswap](https://certificate.quantstamp.com/full/linkswap) + - Lack of return value check + - Uninitialized state variable +- [Cryptex](https://certificate.quantstamp.com/full/cryptex) + - Lack of return value check +## December 2020 +- [Idle](https://certificate.quantstamp.com/full/idle-finance) + - Dangerous divide before multiply operations +- [RariCapital](https://certificate.quantstamp.com/full/rari-capital) + - Lack of return value check + - Uninitialized state variable +- [wfil-factory](https://github.com/wfil/wfil-factory/commit/a43c1ddf52cf1191ccf1e71a637df02d78b98cc0) + - Reentrancy +## January 2021 +- [Origin Dollar](https://github.com/trailofbits/publications/blob/master/reviews/OriginDollar.pdf) + - Reentrancy + - Variable shadowing +- [OriginTrait](https://github.com/OriginTrail/starfleet-boarding-contract/commit/6481b12abc3cfd0d782abd0e32eabd103d8f6953) + - Reentrancy + + From 9e1e564588f493469624d80b1071aa49db44d4ee Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Mon, 11 Jan 2021 12:10:17 +0100 Subject: [PATCH 17/35] Update trophies.md --- trophies.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/trophies.md b/trophies.md index 58899bbc8..42df1b4c7 100644 --- a/trophies.md +++ b/trophies.md @@ -65,6 +65,8 @@ The following lists security vulnerabilities that were found by Slither. If you - Uninitialized state variable - [Cryptex](https://certificate.quantstamp.com/full/cryptex) - Lack of return value check +- [Unoswap](https://www.unos.finance/wp-content/uploads/2020/11/block-audit.pdf) + - Contract locking ethers ## December 2020 - [Idle](https://certificate.quantstamp.com/full/idle-finance) - Dangerous divide before multiply operations From c0acb5f2479ee82a237b9a51b62b4dfdf7599dfd Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Mon, 11 Jan 2021 12:40:55 +0100 Subject: [PATCH 18/35] Update trophies.md --- trophies.md | 69 +++++++++++++++++++++-------------------------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/trophies.md b/trophies.md index 42df1b4c7..a45579652 100644 --- a/trophies.md +++ b/trophies.md @@ -2,84 +2,69 @@ The following lists security vulnerabilities that were found by Slither. If you found a security vulnerability using Slither, please submit a PR with the relevant information. -## October 2018 -- [Basis](https://github.com/trailofbits/publications/blob/master/reviews/basis.pdf) +- October 2018 - [Basis](https://github.com/trailofbits/publications/blob/master/reviews/basis.pdf) - Missing return value check -## November 2018 -- [Origin protocol](https://github.com/trailofbits/publications/blob/master/reviews/origin.pdf) +- November 2018- [Origin protocol](https://github.com/trailofbits/publications/blob/master/reviews/origin.pdf) - Reentrancy -## July 2019 -- [Numerai](https://github.com/trailofbits/publications/blob/master/reviews/numerai.pdf) +- July 2019 - [Numerai](https://github.com/trailofbits/publications/blob/master/reviews/numerai.pdf) - Deletion of a mapping with structure - Missing return value -## September 2019 -- [Flexa](https://github.com/trailofbits/publications/blob/master/reviews/Flexa.pdf) +- September 2019 - [Flexa](https://github.com/trailofbits/publications/blob/master/reviews/Flexa.pdf) - Reentrancy (events out of order) -## October 2019 -- [0x](https://github.com/trailofbits/publications/blob/master/reviews/0x-protocol.pdf) +- October 2019 - [0x](https://github.com/trailofbits/publications/blob/master/reviews/0x-protocol.pdf) - Missing return value -## December 2019 -- [Token mint](https://certificate.quantstamp.com/full/token-mint) +- December 2019 - [Token mint](https://certificate.quantstamp.com/full/token-mint) - Reentrancies -## February 2020 -- [Airswap](https://certificate.quantstamp.com/full/airswap) +- February 2020 - [Airswap](https://certificate.quantstamp.com/full/airswap) - Missing return value check -## March 202 -- [Stake Technologies Lockdrop](https://certificate.quantstamp.com/full/stake-technologies-lockdrop) +- March 202 - [Stake Technologies Lockdrop](https://certificate.quantstamp.com/full/stake-technologies-lockdrop) - Dangerous strict equality -## May 2020 -- [E&Y’s Nightfall](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) +- May 2020 - [E&Y’s Nightfall](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) - Missing return value - Empty return value -- [DefiStrategies](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) +- May 2020 - [DefiStrategies](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) - Modifier can return the default value - Dangerous strict equality allows the contract to be trapped -- [DOSnetwork](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) +- May 2020 - [DOSnetwork](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) - Abi `encodedPacked `collision -- [EthKids](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) +- May 2020 - [EthKids](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) - `msg.value` is used two times to compute a price -- [HQ20](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) +- May 2020 - [HQ20](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) - Reentrancy -## June 2020 -- [88mph](https://certificate.quantstamp.com/full/88-mph) +- June 2020 - [88mph](https://certificate.quantstamp.com/full/88-mph) - Dangerous `block.timestamp` usage -- [Dloop](https://certificate.quantstamp.com/full/dloop-art-registry-smart-contract) +- June 2020 - [Dloop](https://certificate.quantstamp.com/full/dloop-art-registry-smart-contract) - Dangerous `block.timestamp` usage -## July 2020 -- [Atomic Loans](https://certificate.quantstamp.com/full/atomic-loans) +- July 2020 - [Atomic Loans](https://certificate.quantstamp.com/full/atomic-loans) - Uninitialized state variable - State variable shadowing - Reentrancy -- [Parity](https://github.com/trailofbits/publications/blob/master/reviews/parity.pdf) +- July 2020 - [Parity](https://github.com/trailofbits/publications/blob/master/reviews/parity.pdf) - Incorrect constructor name - Deletion of a mapping with structure - Uninitialized state variables -## August 3 2020 -- [Amp](https://github.com/trailofbits/publications/blob/master/reviews/amp.pdf) +- August 2020 - [Amp](https://github.com/trailofbits/publications/blob/master/reviews/amp.pdf) - Duplicate contract name -- [PerlinXRewards](https://certificate.quantstamp.com/full/perlin-x-rewards-sol) +- August 2020 - [PerlinXRewards](https://certificate.quantstamp.com/full/perlin-x-rewards-sol) - Multiple reentrancies -## November 2020 -- [Linkswap](https://certificate.quantstamp.com/full/linkswap) +- November 2020 - [Linkswap](https://certificate.quantstamp.com/full/linkswap) - Lack of return value check - Uninitialized state variable -- [Cryptex](https://certificate.quantstamp.com/full/cryptex) +- November 2020 - [Cryptex](https://certificate.quantstamp.com/full/cryptex) - Lack of return value check -- [Unoswap](https://www.unos.finance/wp-content/uploads/2020/11/block-audit.pdf) +- November 2020 - [Unoswap](https://www.unos.finance/wp-content/uploads/2020/11/block-audit.pdf) - Contract locking ethers -## December 2020 -- [Idle](https://certificate.quantstamp.com/full/idle-finance) +- December 2020 - [Idle](https://certificate.quantstamp.com/full/idle-finance) - Dangerous divide before multiply operations -- [RariCapital](https://certificate.quantstamp.com/full/rari-capital) +- December 2020 - [RariCapital](https://certificate.quantstamp.com/full/rari-capital) - Lack of return value check - Uninitialized state variable -- [wfil-factory](https://github.com/wfil/wfil-factory/commit/a43c1ddf52cf1191ccf1e71a637df02d78b98cc0) +- December 2020 - [wfil-factory](https://github.com/wfil/wfil-factory/commit/a43c1ddf52cf1191ccf1e71a637df02d78b98cc0) - Reentrancy -## January 2021 -- [Origin Dollar](https://github.com/trailofbits/publications/blob/master/reviews/OriginDollar.pdf) +- January 2021 - [Origin Dollar](https://github.com/trailofbits/publications/blob/master/reviews/OriginDollar.pdf) - Reentrancy - Variable shadowing -- [OriginTrait](https://github.com/OriginTrail/starfleet-boarding-contract/commit/6481b12abc3cfd0d782abd0e32eabd103d8f6953) +- January 2021 - [OriginTrait](https://github.com/OriginTrail/starfleet-boarding-contract/commit/6481b12abc3cfd0d782abd0e32eabd103d8f6953) - Reentrancy From cdcb1698c6de189c1d14d538be6b3b283c147c9e Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Mon, 11 Jan 2021 12:42:17 +0100 Subject: [PATCH 19/35] Update trophies.md --- trophies.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trophies.md b/trophies.md index a45579652..072d72067 100644 --- a/trophies.md +++ b/trophies.md @@ -4,7 +4,7 @@ The following lists security vulnerabilities that were found by Slither. If you - October 2018 - [Basis](https://github.com/trailofbits/publications/blob/master/reviews/basis.pdf) - Missing return value check -- November 2018- [Origin protocol](https://github.com/trailofbits/publications/blob/master/reviews/origin.pdf) +- November 2018 - [Origin protocol](https://github.com/trailofbits/publications/blob/master/reviews/origin.pdf) - Reentrancy - July 2019 - [Numerai](https://github.com/trailofbits/publications/blob/master/reviews/numerai.pdf) - Deletion of a mapping with structure From 670664685972d17213261ddb22f992b5e2001f35 Mon Sep 17 00:00:00 2001 From: Josselin Date: Wed, 13 Jan 2021 17:16:53 +0100 Subject: [PATCH 20/35] run markdownlinter --- trophies.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/trophies.md b/trophies.md index 072d72067..c5201f0ae 100644 --- a/trophies.md +++ b/trophies.md @@ -1,11 +1,13 @@ # Slither Trophies -The following lists security vulnerabilities that were found by Slither. If you found a security vulnerability using Slither, please submit a PR with the relevant information. +The following lists security vulnerabilities that were found by Slither. +If you found a security vulnerability using Slither, +please submit a PR with the relevant information. - October 2018 - [Basis](https://github.com/trailofbits/publications/blob/master/reviews/basis.pdf) - Missing return value check -- November 2018 - [Origin protocol](https://github.com/trailofbits/publications/blob/master/reviews/origin.pdf) - - Reentrancy +- November 2018 - [Origin protocol](https://github.com/trailofbits/publications/blob/master/reviews/origin.pdf) + - Reentrancy - July 2019 - [Numerai](https://github.com/trailofbits/publications/blob/master/reviews/numerai.pdf) - Deletion of a mapping with structure - Missing return value @@ -26,7 +28,7 @@ The following lists security vulnerabilities that were found by Slither. If you - Modifier can return the default value - Dangerous strict equality allows the contract to be trapped - May 2020 - [DOSnetwork](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) - - Abi `encodedPacked `collision + - Abi `encodedPacked` collision - May 2020 - [EthKids](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) - `msg.value` is used two times to compute a price - May 2020 - [HQ20](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) @@ -61,10 +63,8 @@ The following lists security vulnerabilities that were found by Slither. If you - Uninitialized state variable - December 2020 - [wfil-factory](https://github.com/wfil/wfil-factory/commit/a43c1ddf52cf1191ccf1e71a637df02d78b98cc0) - Reentrancy -- January 2021 - [Origin Dollar](https://github.com/trailofbits/publications/blob/master/reviews/OriginDollar.pdf) +- January 2021 - [Origin Dollar](https://github.com/trailofbits/publications/blob/master/reviews/OriginDollar.pdf) - Reentrancy - Variable shadowing - January 2021 - [OriginTrait](https://github.com/OriginTrail/starfleet-boarding-contract/commit/6481b12abc3cfd0d782abd0e32eabd103d8f6953) - Reentrancy - - From e8f4f4288600b626aee63726ffdffde07cf989d4 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Wed, 13 Jan 2021 18:05:42 +0100 Subject: [PATCH 21/35] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 196a569f8..1022e4cc5 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Slither is a Solidity static analysis framework written in Python 3. It runs a s ## Features -* Detects vulnerable Solidity code with low false positives +* Detects vulnerable Solidity code with low false positives (see the list of [trophies](./trophies.md)) * Identifies where the error condition occurs in the source code * Easily integrates into continuous integration and Truffle builds * Built-in 'printers' quickly report crucial contract information From c0c581b3ba830b6ce8dc3f4be82592a7a42e9752 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Thu, 14 Jan 2021 20:24:05 +0100 Subject: [PATCH 22/35] Update trophies.md --- trophies.md | 103 ++++++++++++++++++++-------------------------------- 1 file changed, 39 insertions(+), 64 deletions(-) diff --git a/trophies.md b/trophies.md index c5201f0ae..bc33c20dd 100644 --- a/trophies.md +++ b/trophies.md @@ -4,67 +4,42 @@ The following lists security vulnerabilities that were found by Slither. If you found a security vulnerability using Slither, please submit a PR with the relevant information. -- October 2018 - [Basis](https://github.com/trailofbits/publications/blob/master/reviews/basis.pdf) - - Missing return value check -- November 2018 - [Origin protocol](https://github.com/trailofbits/publications/blob/master/reviews/origin.pdf) - - Reentrancy -- July 2019 - [Numerai](https://github.com/trailofbits/publications/blob/master/reviews/numerai.pdf) - - Deletion of a mapping with structure - - Missing return value -- September 2019 - [Flexa](https://github.com/trailofbits/publications/blob/master/reviews/Flexa.pdf) - - Reentrancy (events out of order) -- October 2019 - [0x](https://github.com/trailofbits/publications/blob/master/reviews/0x-protocol.pdf) - - Missing return value -- December 2019 - [Token mint](https://certificate.quantstamp.com/full/token-mint) - - Reentrancies -- February 2020 - [Airswap](https://certificate.quantstamp.com/full/airswap) - - Missing return value check -- March 202 - [Stake Technologies Lockdrop](https://certificate.quantstamp.com/full/stake-technologies-lockdrop) - - Dangerous strict equality -- May 2020 - [E&Y’s Nightfall](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) - - Missing return value - - Empty return value -- May 2020 - [DefiStrategies](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) - - Modifier can return the default value - - Dangerous strict equality allows the contract to be trapped -- May 2020 - [DOSnetwork](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) - - Abi `encodedPacked` collision -- May 2020 - [EthKids](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) - - `msg.value` is used two times to compute a price -- May 2020 - [HQ20](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) - - Reentrancy -- June 2020 - [88mph](https://certificate.quantstamp.com/full/88-mph) - - Dangerous `block.timestamp` usage -- June 2020 - [Dloop](https://certificate.quantstamp.com/full/dloop-art-registry-smart-contract) - - Dangerous `block.timestamp` usage -- July 2020 - [Atomic Loans](https://certificate.quantstamp.com/full/atomic-loans) - - Uninitialized state variable - - State variable shadowing - - Reentrancy -- July 2020 - [Parity](https://github.com/trailofbits/publications/blob/master/reviews/parity.pdf) - - Incorrect constructor name - - Deletion of a mapping with structure - - Uninitialized state variables -- August 2020 - [Amp](https://github.com/trailofbits/publications/blob/master/reviews/amp.pdf) - - Duplicate contract name -- August 2020 - [PerlinXRewards](https://certificate.quantstamp.com/full/perlin-x-rewards-sol) - - Multiple reentrancies -- November 2020 - [Linkswap](https://certificate.quantstamp.com/full/linkswap) - - Lack of return value check - - Uninitialized state variable -- November 2020 - [Cryptex](https://certificate.quantstamp.com/full/cryptex) - - Lack of return value check -- November 2020 - [Unoswap](https://www.unos.finance/wp-content/uploads/2020/11/block-audit.pdf) - - Contract locking ethers -- December 2020 - [Idle](https://certificate.quantstamp.com/full/idle-finance) - - Dangerous divide before multiply operations -- December 2020 - [RariCapital](https://certificate.quantstamp.com/full/rari-capital) - - Lack of return value check - - Uninitialized state variable -- December 2020 - [wfil-factory](https://github.com/wfil/wfil-factory/commit/a43c1ddf52cf1191ccf1e71a637df02d78b98cc0) - - Reentrancy -- January 2021 - [Origin Dollar](https://github.com/trailofbits/publications/blob/master/reviews/OriginDollar.pdf) - - Reentrancy - - Variable shadowing -- January 2021 - [OriginTrait](https://github.com/OriginTrail/starfleet-boarding-contract/commit/6481b12abc3cfd0d782abd0e32eabd103d8f6953) - - Reentrancy +| Project | Vulnerability | Date | +|--|--|--| +[Parity](https://github.com/trailofbits/publications/blob/master/reviews/parity.pdf) | Incorrect constructor name | July 2018 +[Parity](https://github.com/trailofbits/publications/blob/master/reviews/parity.pdf) | Deletion of a mapping with structure | July 2018 +[Parity](https://github.com/trailofbits/publications/blob/master/reviews/parity.pdf) | Uninitialized state variables | July 2018 +[Basis](https://github.com/trailofbits/publications/blob/master/reviews/basis.pdf) | Missing return value check | Oct 2018 +[Origin protocol](https://github.com/trailofbits/publications/blob/master/reviews/origin.pdf) | Reentrancy | Nov 2018 +[Numerai](https://github.com/trailofbits/publications/blob/master/reviews/numerai.pdf) | Deletion of a mapping with structure | Jul 2019 +[Numerai](https://github.com/trailofbits/publications/blob/master/reviews/numerai.pdf) | Missing return value | Jul 2019 +[Flexa](https://github.com/trailofbits/publications/blob/master/reviews/Flexa.pdf) | Reentrancy (events out of order) | Sep 2019 +[0x](https://github.com/trailofbits/publications/blob/master/reviews/0x-protocol.pdf) | Missing return value | Oct 2019 +[Token mint](https://certificate.quantstamp.com/full/token-mint) | Reentrancies | Dec 2019 +[Airswap](https://certificate.quantstamp.com/full/airswap) | Missing return value check | Feb 2020 +[Stake Technologies Lockdrop](https://certificate.quantstamp.com/full/stake-technologies-lockdrop) | Dangerous strict equality | Mar 2020 +[E&Y’s Nightfall](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Missing return value | May 2020 +[E&Y’s Nightfall](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Empty return value | May 2020 +[DefiStrategies](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Modifier can return the default value | May 2020 +[DefiStrategies](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Dangerous strict equality allows the contract to be trapped | May 2020 +[DOSnetwork](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Abi `encodedPacked` collision | May 2020 +[EthKids](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | `msg.value` is used two times to compute a price | May 2020 +[HQ20](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Reentrancy | May 2020 +[88mph](https://certificate.quantstamp.com/full/88-mph) | Dangerous `block.timestamp` usage | Jun 2020 +[Dloop](https://certificate.quantstamp.com/full/dloop-art-registry-smart-contract) | Dangerous `block.timestamp` usage | Jun 2020 +[Atomic Loans](https://certificate.quantstamp.com/full/atomic-loans) | Uninitialized state variable | Jul 2020 +[Atomic Loans](https://certificate.quantstamp.com/full/atomic-loans) | State variable shadowing | Jul 2020 +[Atomic Loans](https://certificate.quantstamp.com/full/atomic-loans) | Reentrancy | Jul 2020 +[Amp](https://github.com/trailofbits/publications/blob/master/reviews/amp.pdf) | Duplicate contract name | Aug 2020 +[PerlinXRewards](https://certificate.quantstamp.com/full/perlin-x-rewards-sol) | Multiple reentrancies | Aug 2020 +[Linkswap](https://certificate.quantstamp.com/full/linkswap) | Lack of return value check | Nov 2020 +[Linkswap](https://certificate.quantstamp.com/full/linkswap) | Uninitialized state variable | Nov 2020 +[Cryptex](https://certificate.quantstamp.com/full/cryptex) | Lack of return value check | Nov 2020 +[Unoswap](https://www.unos.finance/wp-content/uploads/2020/11/block-audit.pdf) | Contract locking ethers | Nov 2020 +[Idle](https://certificate.quantstamp.com/full/idle-finance) | Dangerous divide before multiply operations | Dec 2020 +[RariCapital](https://certificate.quantstamp.com/full/rari-capital) | Lack of return value check | Dec 2020 +[RariCapital](https://certificate.quantstamp.com/full/rari-capital) | Uninitialized state variable | Dec 2020 +[wfil-factory](https://github.com/wfil/wfil-factory/commit/a43c1ddf52cf1191ccf1e71a637df02d78b98cc0) | Reentrancy | Dec 2020 +[Origin Dollar](https://github.com/trailofbits/publications/blob/master/reviews/OriginDollar.pdf) | Reentrancy | Jan 2021 +[Origin Dollar](https://github.com/trailofbits/publications/blob/master/reviews/OriginDollar.pdf) | Variable shadowing | Jan 2021 +[OriginTrait](https://github.com/OriginTrail/starfleet-boarding-contract/commit/6481b12abc3cfd0d782abd0e32eabd103d8f6953) | Reentrancy | Jan 2021 From f5ca637c34b33cd3c7c022f524396fbd53f20383 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Thu, 21 Jan 2021 13:05:56 +0100 Subject: [PATCH 23/35] Update external publications --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1022e4cc5..b944c8f7f 100644 --- a/README.md +++ b/README.md @@ -217,5 +217,6 @@ Slither is licensed and distributed under the AGPLv3 license. [Contact us](mailt - [ETHPLOIT: From Fuzzing to Efficient Exploit Generation against Smart Contracts](https://wcventure.github.io/FuzzingPaper/Paper/SANER20_ETHPLOIT.pdf), Qingzhao Zhang, Yizhuo Wang, Juanru Li, Siqi Ma - SANER 20 - [Verification of Ethereum Smart Contracts: A Model Checking Approach](http://www.ijmlc.org/vol10/977-AM0059.pdf), Tam Bang, Hoang H Nguyen, Dung Nguyen, Toan Trieu, Tho Quan - IJMLC 20 - [Smart Contract Repair](https://arxiv.org/pdf/1912.05823.pdf), Xiao Liang Yu, Omar Al-Bataineh, David Lo, Abhik Roychoudhury - TOSEM 20 +- [Demystifying Loops in Smart Contracts](https://www.microsoft.com/en-us/research/uploads/prod/2020/08/loops_solidity__camera_ready-5f3fec3f15c69.pdf), Ben Mariano, Yanju Chen, Yu Feng, Shuvendu Lahiri, Isil Dillig - ASE 20 If you are using Slither on an academic work, consider applying to the [Crytic $10k Research Prize](https://blog.trailofbits.com/2019/11/13/announcing-the-crytic-10k-research-prize/). From 8afd4227120d35ec3f216158e2402cb8da06f929 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Thu, 28 Jan 2021 14:38:57 +0100 Subject: [PATCH 24/35] disable jscp from gh super linter --- .github/workflows/linter.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index c2720d5ae..2629567bb 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -80,4 +80,5 @@ jobs: VALIDATE_DOCKERFILE: false VALIDATE_DOCKERFILE_HADOLINT: false VALIDATE_EDITORCONFIG: false + VALIDATE_JSCPD: false SHELLCHECK_OPTS: "-e SC1090" From d10fe9a0fe0f18a7da027b043c9cd165e9e8a37f Mon Sep 17 00:00:00 2001 From: Franco Victorio Date: Mon, 1 Feb 2021 09:25:59 -0300 Subject: [PATCH 25/35] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b944c8f7f..d68f2aa00 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Slither is a Solidity static analysis framework written in Python 3. It runs a s ## Bugs and Optimizations Detection -Run Slither on a Truffle/Embark/Dapp/Etherlime application: +Run Slither on a Truffle/Embark/Dapp/Etherlime/Hardhat application: ```bash slither . ``` From 90cd5f0b26f785b9ee11bb87a7dfbced96a44332 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Mon, 8 Feb 2021 09:57:55 +0100 Subject: [PATCH 26/35] Add hermez reentrancy to trophies.md --- trophies.md | 1 + 1 file changed, 1 insertion(+) diff --git a/trophies.md b/trophies.md index bc33c20dd..0cccf5579 100644 --- a/trophies.md +++ b/trophies.md @@ -35,6 +35,7 @@ please submit a PR with the relevant information. [Linkswap](https://certificate.quantstamp.com/full/linkswap) | Lack of return value check | Nov 2020 [Linkswap](https://certificate.quantstamp.com/full/linkswap) | Uninitialized state variable | Nov 2020 [Cryptex](https://certificate.quantstamp.com/full/cryptex) | Lack of return value check | Nov 2020 +[Hermez](https://github.com/trailofbits/publications/blob/master/reviews/hermez.pdf) | Reentrancy | Nov 2020 [Unoswap](https://www.unos.finance/wp-content/uploads/2020/11/block-audit.pdf) | Contract locking ethers | Nov 2020 [Idle](https://certificate.quantstamp.com/full/idle-finance) | Dangerous divide before multiply operations | Dec 2020 [RariCapital](https://certificate.quantstamp.com/full/rari-capital) | Lack of return value check | Dec 2020 From cc01a1f5fec85a9a6684613863b1e0f754d0b82e Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Tue, 9 Feb 2021 11:41:31 +0100 Subject: [PATCH 27/35] Update trophies.md --- trophies.md | 1 - 1 file changed, 1 deletion(-) diff --git a/trophies.md b/trophies.md index 0cccf5579..55383790f 100644 --- a/trophies.md +++ b/trophies.md @@ -25,7 +25,6 @@ please submit a PR with the relevant information. [DOSnetwork](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Abi `encodedPacked` collision | May 2020 [EthKids](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | `msg.value` is used two times to compute a price | May 2020 [HQ20](https://blog.trailofbits.com/2020/05/15/bug-hunting-with-crytic/) | Reentrancy | May 2020 -[88mph](https://certificate.quantstamp.com/full/88-mph) | Dangerous `block.timestamp` usage | Jun 2020 [Dloop](https://certificate.quantstamp.com/full/dloop-art-registry-smart-contract) | Dangerous `block.timestamp` usage | Jun 2020 [Atomic Loans](https://certificate.quantstamp.com/full/atomic-loans) | Uninitialized state variable | Jul 2020 [Atomic Loans](https://certificate.quantstamp.com/full/atomic-loans) | State variable shadowing | Jul 2020 From 8d9e162eb368ce4967f432ac776a15ee4acf1862 Mon Sep 17 00:00:00 2001 From: Josselin Date: Sun, 14 Feb 2021 18:30:50 +0100 Subject: [PATCH 28/35] User __str__ for top level user defined type (fix #773) --- slither/core/solidity_types/user_defined_type.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/slither/core/solidity_types/user_defined_type.py b/slither/core/solidity_types/user_defined_type.py index 75a44e10f..cecbec449 100644 --- a/slither/core/solidity_types/user_defined_type.py +++ b/slither/core/solidity_types/user_defined_type.py @@ -59,12 +59,13 @@ class UserDefinedType(Type): raise SlitherException(to_log) def __str__(self): - from slither.core.declarations.structure import Structure - from slither.core.declarations.enum import Enum + from slither.core.declarations.structure_contract import StructureContract + from slither.core.declarations.enum_contract import EnumContract - if isinstance(self.type, (Enum, Structure)): - return str(self.type.contract) + "." + str(self.type.name) - return str(self.type.name) + type_used = self.type + if isinstance(type_used, (EnumContract, StructureContract)): + return str(type_used.contract) + "." + str(type_used.name) + return str(type_used.name) def __eq__(self, other): if not isinstance(other, UserDefinedType): From d401aa19f8b19374ed9fc222403963cf026bdd50 Mon Sep 17 00:00:00 2001 From: Josselin Date: Sun, 14 Feb 2021 18:34:59 +0100 Subject: [PATCH 29/35] Use python version of solc-select in CI --- .github/workflows/ci.yml | 5 +---- .github/workflows/detectors.yml | 6 +----- .github/workflows/parser.yml | 6 +----- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a21519b7..d3b1421fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,10 +45,7 @@ jobs: # Used by ci_test.sh pip install deepdiff - git clone https://github.com/crytic/solc-select.git - ./solc-select/scripts/install.sh - export PATH=/home/runner/.solc-select:$PATH - echo "export PATH=/home/runner/.solc-select:$PATH" >> ~/.bashrc + pip install solc-select solc use 0.5.1 - name: Run Tests diff --git a/.github/workflows/detectors.yml b/.github/workflows/detectors.yml index cbd4a2f92..64b32cea8 100644 --- a/.github/workflows/detectors.yml +++ b/.github/workflows/detectors.yml @@ -33,11 +33,7 @@ jobs: pip install deepdiff pip install pytest - git clone https://github.com/crytic/solc-select.git - ./solc-select/scripts/install.sh - export PATH=/home/runner/.solc-select:$PATH - echo "export PATH=/home/runner/.solc-select:$PATH" >> ~/.bashrc - + pip install solc-select - name: Test with pytest run: | pytest tests/test_detectors.py diff --git a/.github/workflows/parser.yml b/.github/workflows/parser.yml index bfa687f42..5f09fcd80 100644 --- a/.github/workflows/parser.yml +++ b/.github/workflows/parser.yml @@ -32,11 +32,7 @@ jobs: python setup.py install pip install deepdiff pip install pytest - - git clone https://github.com/crytic/solc-select.git - ./solc-select/scripts/install.sh - export PATH=/home/runner/.solc-select:$PATH - echo "export PATH=/home/runner/.solc-select:$PATH" >> ~/.bashrc + pip install solc-select - name: Test with pytest run: | From 13e6939a935cfdf90ae5694cdf9e69ea0f6e85fc Mon Sep 17 00:00:00 2001 From: Josselin Date: Sun, 14 Feb 2021 18:46:05 +0100 Subject: [PATCH 30/35] Improvements --- .github/workflows/ci.yml | 3 ++- .github/workflows/detectors.yml | 2 ++ .github/workflows/parser.yml | 2 ++ scripts/ci_test_cli.sh | 2 +- scripts/ci_test_erc.sh | 2 +- scripts/ci_test_find_paths.sh | 2 +- scripts/ci_test_kspec.sh | 2 +- scripts/ci_test_printers.sh | 2 +- scripts/ci_test_simil.sh | 2 +- scripts/ci_test_upgradability.sh | 2 +- 10 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3b1421fa..65f49b685 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,8 @@ jobs: pip install deepdiff pip install solc-select - solc use 0.5.1 + solc-select install all + solc-select use 0.5.1 - name: Run Tests env: diff --git a/.github/workflows/detectors.yml b/.github/workflows/detectors.yml index 64b32cea8..13f4ca6ff 100644 --- a/.github/workflows/detectors.yml +++ b/.github/workflows/detectors.yml @@ -34,6 +34,8 @@ jobs: pip install pytest pip install solc-select + solc-select install all + solc-select use 0.7.3 - name: Test with pytest run: | pytest tests/test_detectors.py diff --git a/.github/workflows/parser.yml b/.github/workflows/parser.yml index 5f09fcd80..60cb0cb9b 100644 --- a/.github/workflows/parser.yml +++ b/.github/workflows/parser.yml @@ -33,6 +33,8 @@ jobs: pip install deepdiff pip install pytest pip install solc-select + solc-select install all + solc-select use 0.7.3 - name: Test with pytest run: | diff --git a/scripts/ci_test_cli.sh b/scripts/ci_test_cli.sh index fcdc960ff..9bfe63d5b 100755 --- a/scripts/ci_test_cli.sh +++ b/scripts/ci_test_cli.sh @@ -2,7 +2,7 @@ ### Test -solc use 0.7.0 +solc-select use 0.7.0 if ! slither "tests/config/test.sol" --solc-ast --ignore-return-value; then echo "--solc-ast failed" diff --git a/scripts/ci_test_erc.sh b/scripts/ci_test_erc.sh index a96a414e1..ce9a62363 100755 --- a/scripts/ci_test_erc.sh +++ b/scripts/ci_test_erc.sh @@ -4,7 +4,7 @@ DIR_TESTS="tests/check-erc" -solc use 0.5.0 +solc-select use 0.5.0 slither-check-erc "$DIR_TESTS/erc20.sol" ERC20 > test_1.txt 2>&1 DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt") if [ "$DIFF" != "" ] diff --git a/scripts/ci_test_find_paths.sh b/scripts/ci_test_find_paths.sh index 2707aaa07..a916fb5a9 100755 --- a/scripts/ci_test_find_paths.sh +++ b/scripts/ci_test_find_paths.sh @@ -4,7 +4,7 @@ DIR_TESTS="tests/possible_paths" -solc use "0.5.0" +solc-select use "0.5.0" slither-find-paths "$DIR_TESTS/paths.sol" A.destination > test_possible_paths.txt 2>&1 DIFF=$(diff test_possible_paths.txt "$DIR_TESTS/paths.txt") if [ "$DIFF" != "" ] diff --git a/scripts/ci_test_kspec.sh b/scripts/ci_test_kspec.sh index c80df54e0..cb0a131a8 100755 --- a/scripts/ci_test_kspec.sh +++ b/scripts/ci_test_kspec.sh @@ -2,7 +2,7 @@ DIR_TESTS="tests/check-kspec" -solc use "0.5.0" +solc-select use "0.5.0" slither-check-kspec "$DIR_TESTS/safeAdd/safeAdd.sol" "$DIR_TESTS/safeAdd/spec.md" > test_1.txt 2>&1 DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt") if [ "$DIFF" != "" ] diff --git a/scripts/ci_test_printers.sh b/scripts/ci_test_printers.sh index 209f4329e..1acfff3f1 100755 --- a/scripts/ci_test_printers.sh +++ b/scripts/ci_test_printers.sh @@ -10,6 +10,6 @@ if ! slither "tests/*.json" --print all --json -; then exit 1 fi -solc use "0.5.1" +solc-select use "0.5.1" slither examples/scripts/test_evm_api.sol --print evm diff --git a/scripts/ci_test_simil.sh b/scripts/ci_test_simil.sh index 5c8a8f70d..bad5fd067 100755 --- a/scripts/ci_test_simil.sh +++ b/scripts/ci_test_simil.sh @@ -7,7 +7,7 @@ pip3.6 install https://github.com/facebookresearch/fastText/archive/0.2.0.zip ### Test slither-simil -solc use "0.4.25" +solc-select use "0.4.25" DIR_TESTS="tests/simil" slither-simil info "" --filename $DIR_TESTS/../complex_func.sol --fname Complex.complexExternalWrites > test_1.txt 2>&1 diff --git a/scripts/ci_test_upgradability.sh b/scripts/ci_test_upgradability.sh index 2dd8f7a52..b34564003 100755 --- a/scripts/ci_test_upgradability.sh +++ b/scripts/ci_test_upgradability.sh @@ -3,7 +3,7 @@ ### Test slither-check-upgradeability DIR_TESTS="tests/check-upgradeability" -solc use "0.5.0" +solc-select use "0.5.0" slither-check-upgradeability "$DIR_TESTS/contractV1.sol" ContractV1 --proxy-filename "$DIR_TESTS/proxy.sol" --proxy-name Proxy > test_1.txt 2>&1 DIFF=$(diff test_1.txt "$DIR_TESTS/test_1.txt") From ba7babc15cbe117201ea2b0406d4921696d088db Mon Sep 17 00:00:00 2001 From: Josselin Date: Sun, 14 Feb 2021 18:50:20 +0100 Subject: [PATCH 31/35] Fix test_ast_parsing --- tests/test_ast_parsing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index c37700324..33eabad5a 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -411,7 +411,7 @@ def get_solc_versions() -> List[str]: get a list of all the supported versions of solidity, sorted from earliest to latest :return: ascending list of versions, for example ["0.4.0", "0.4.1", ...] """ - result = subprocess.run(["solc", "--versions"], stdout=subprocess.PIPE, check=True) + result = subprocess.run(["solc-select", "versions"], stdout=subprocess.PIPE, check=True) solc_versions = result.stdout.decode("utf-8").split("\n") # there's an extra newline so just remove all empty strings From 196dd342fb46294b5c7d92bc984e0f8c5dcaaf7c Mon Sep 17 00:00:00 2001 From: Josselin Date: Mon, 15 Feb 2021 10:02:35 +0100 Subject: [PATCH 32/35] Revert to docker version of solc select for the parsing tests (see https://github.com/crytic/solc-select/issues/41) --- .github/workflows/parser.yml | 12 +++++++++--- tests/test_ast_parsing.py | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/parser.yml b/.github/workflows/parser.yml index 60cb0cb9b..c7db98197 100644 --- a/.github/workflows/parser.yml +++ b/.github/workflows/parser.yml @@ -32,9 +32,15 @@ jobs: python setup.py install pip install deepdiff pip install pytest - pip install solc-select - solc-select install all - solc-select use 0.7.3 + + git clone https://github.com/crytic/solc-select.git + cd solc-select + git checkout 857d6fa883d9283454be1cb2d869a8f9962b27b8 + cd .. + ./solc-select/scripts/install.sh + export PATH=/home/runner/.solc-select:$PATH + echo "export PATH=/home/runner/.solc-select:$PATH" >> ~/.bashrc + solc use 0.7.3 - name: Test with pytest run: | diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index 33eabad5a..c37700324 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -411,7 +411,7 @@ def get_solc_versions() -> List[str]: get a list of all the supported versions of solidity, sorted from earliest to latest :return: ascending list of versions, for example ["0.4.0", "0.4.1", ...] """ - result = subprocess.run(["solc-select", "versions"], stdout=subprocess.PIPE, check=True) + result = subprocess.run(["solc", "--versions"], stdout=subprocess.PIPE, check=True) solc_versions = result.stdout.decode("utf-8").split("\n") # there's an extra newline so just remove all empty strings From 6f471487ab5139b122a89cc70f8e016f392aa03f Mon Sep 17 00:00:00 2001 From: Nat Date: Tue, 23 Feb 2021 10:55:07 +0000 Subject: [PATCH 33/35] Rename __init__.y.py to __init__.py Fix flattening.export package so that it is correctly included in installed package. --- slither/tools/flattening/export/__init__.py | 1 + slither/tools/flattening/export/__init__.y.py | 0 2 files changed, 1 insertion(+) create mode 100644 slither/tools/flattening/export/__init__.py delete mode 100644 slither/tools/flattening/export/__init__.y.py diff --git a/slither/tools/flattening/export/__init__.py b/slither/tools/flattening/export/__init__.py new file mode 100644 index 000000000..d3f5a12fa --- /dev/null +++ b/slither/tools/flattening/export/__init__.py @@ -0,0 +1 @@ + diff --git a/slither/tools/flattening/export/__init__.y.py b/slither/tools/flattening/export/__init__.y.py deleted file mode 100644 index e69de29bb..000000000 From 526a156d0ab163c27d894ecddbcaca6e5c6a94ce Mon Sep 17 00:00:00 2001 From: Josselin Date: Sun, 7 Mar 2021 17:21:38 +0100 Subject: [PATCH 34/35] Update to pylint `2.8.2` black `20.8b1`. --- CONTRIBUTING.md | 2 +- plugin_example/setup.py | 4 +- slither/__main__.py | 15 ++++- .../data_dependency/data_dependency.py | 19 +++++- .../analyses/write/are_variables_written.py | 5 +- slither/core/cfg/node.py | 8 ++- slither/core/declarations/function.py | 17 ++++-- slither/core/solidity_types/function_type.py | 4 +- slither/detectors/attributes/locked_ether.py | 3 +- slither/detectors/functions/arbitrary_send.py | 8 ++- .../naming_convention/naming_convention.py | 18 ++++-- .../detectors/operations/block_timestamp.py | 4 +- slither/detectors/reentrancy/reentrancy.py | 3 +- .../detectors/reentrancy/reentrancy_benign.py | 12 +++- .../detectors/reentrancy/reentrancy_eth.py | 10 +++- .../detectors/reentrancy/reentrancy_events.py | 12 +++- .../detectors/reentrancy/reentrancy_no_gas.py | 18 ++++-- .../reentrancy_read_before_write.py | 7 ++- .../statements/incorrect_strict_equality.py | 6 +- .../statements/unprotected_upgradeable.py | 4 +- .../formatters/attributes/constant_pragma.py | 7 ++- .../naming_convention/naming_convention.py | 7 ++- slither/printers/call/call_graph.py | 58 +++++++++++++++---- slither/printers/functions/authorization.py | 6 +- slither/printers/summary/evm.py | 6 +- slither/printers/summary/function.py | 19 +++++- slither/printers/summary/human_summary.py | 9 ++- slither/printers/summary/require_calls.py | 5 +- slither/slithir/convert.py | 26 +++++++-- slither/slithir/operations/binary.py | 6 +- slither/slithir/operations/library_call.py | 6 +- slither/slithir/tmp_operations/tmp_call.py | 9 ++- slither/slithir/utils/ssa.py | 18 +++++- slither/slithir/utils/utils.py | 9 ++- slither/solc_parsing/declarations/contract.py | 3 +- slither/solc_parsing/declarations/function.py | 8 ++- .../declarations/structure_contract.py | 5 +- .../declarations/structure_top_level.py | 5 +- .../expressions/expression_parsing.py | 15 +++-- slither/solc_parsing/slitherSolc.py | 12 +++- .../solidity_types/type_parsing.py | 3 +- slither/solc_parsing/yul/parse_yul.py | 11 +++- slither/tools/erc_conformance/__main__.py | 3 +- slither/tools/flattening/__main__.py | 13 ++++- slither/tools/flattening/export/export.py | 4 +- slither/tools/flattening/flattening.py | 15 ++++- slither/tools/kspec_coverage/__main__.py | 11 +++- slither/tools/possible_paths/__main__.py | 3 +- .../tools/possible_paths/possible_paths.py | 3 +- slither/tools/properties/__main__.py | 4 +- slither/tools/properties/properties/erc20.py | 6 +- .../ercs/erc20/unit_tests/truffle.py | 11 +++- slither/tools/similarity/__main__.py | 5 +- slither/tools/slither_format/__main__.py | 11 +++- .../tools/slither_format/slither_format.py | 5 +- slither/tools/upgradeability/__main__.py | 5 +- slither/utils/erc.py | 43 ++++++++++++-- slither/utils/expression_manipulations.py | 12 +++- slither/utils/inheritance_analysis.py | 4 +- slither/utils/output.py | 44 +++++++++++--- .../visitors/slithir/expression_to_slithir.py | 12 +++- tests/test_ast_parsing.py | 10 +++- 62 files changed, 523 insertions(+), 133 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3cb03359e..b4732836c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,7 +37,7 @@ To run them locally in the root dir of the repository: - `pylint slither tests --rcfile pyproject.toml` - `black . --config pyproject.toml` -We use black `19.10b0`. +We use pylint `2.8.2` black `20.8b1`. ### Detectors tests For each new detector, at least one regression tests must be present. diff --git a/plugin_example/setup.py b/plugin_example/setup.py index 36e274128..9cef2aaf9 100644 --- a/plugin_example/setup.py +++ b/plugin_example/setup.py @@ -9,5 +9,7 @@ setup( packages=find_packages(), python_requires=">=3.6", install_requires=["slither-analyzer==0.1"], - entry_points={"slither_analyzer.plugin": "slither my-plugin=slither_my_plugin:make_plugin",}, + entry_points={ + "slither_analyzer.plugin": "slither my-plugin=slither_my_plugin:make_plugin", + }, ) diff --git a/slither/__main__.py b/slither/__main__.py index 3bb55b8a3..feab39f3d 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -412,7 +412,10 @@ def parse_args(detector_classes, printer_classes): # pylint: disable=too-many-s ) group_misc.add_argument( - "--markdown-root", help="URL for markdown generation", action="store", default="", + "--markdown-root", + help="URL for markdown generation", + action="store", + default="", ) group_misc.add_argument( @@ -447,7 +450,10 @@ def parse_args(detector_classes, printer_classes): # pylint: disable=too-many-s ) group_misc.add_argument( - "--solc-ast", help="Provide the contract as a json AST", action="store_true", default=False, + "--solc-ast", + help="Provide the contract as a json AST", + action="store_true", + default=False, ) group_misc.add_argument( @@ -500,7 +506,10 @@ def parse_args(detector_classes, printer_classes): # pylint: disable=too-many-s ) parser.add_argument( - "--perf", help=argparse.SUPPRESS, action="store_true", default=False, + "--perf", + help=argparse.SUPPRESS, + action="store_true", + default=False, ) # if the json is splitted in different files diff --git a/slither/analyses/data_dependency/data_dependency.py b/slither/analyses/data_dependency/data_dependency.py index 9ddcd9c4d..27109db73 100644 --- a/slither/analyses/data_dependency/data_dependency.py +++ b/slither/analyses/data_dependency/data_dependency.py @@ -136,7 +136,9 @@ def is_tainted_ssa(variable, context, only_unprotected=False, ignore_generic_tai def get_dependencies( - variable: Variable, context: Union[Contract, Function], only_unprotected: bool = False, + variable: Variable, + context: Union[Contract, Function], + only_unprotected: bool = False, ) -> Set[Variable]: """ Return the variables for which `variable` depends on. @@ -171,7 +173,9 @@ def get_all_dependencies( def get_dependencies_ssa( - variable: Variable, context: Union[Contract, Function], only_unprotected: bool = False, + variable: Variable, + context: Union[Contract, Function], + only_unprotected: bool = False, ) -> Set[Variable]: """ Return the variables for which `variable` depends on (SSA version). @@ -382,7 +386,16 @@ def convert_variable_to_non_ssa(v): return v.non_ssa_version assert isinstance( v, - (Constant, SolidityVariable, Contract, Enum, SolidityFunction, Structure, Function, Type,), + ( + Constant, + SolidityVariable, + Contract, + Enum, + SolidityFunction, + Structure, + Function, + Type, + ), ) return v diff --git a/slither/analyses/write/are_variables_written.py b/slither/analyses/write/are_variables_written.py index 7d1436884..80a115f7a 100644 --- a/slither/analyses/write/are_variables_written.py +++ b/slither/analyses/write/are_variables_written.py @@ -35,7 +35,10 @@ class State: # pylint: disable=too-few-public-methods # pylint: disable=too-many-branches def _visit( - node: Node, state: State, variables_written: Set[Variable], variables_to_write: List[Variable], + node: Node, + state: State, + variables_written: Set[Variable], + variables_to_write: List[Variable], ): """ Explore all the nodes to look for values not written when the node's function return diff --git a/slither/core/cfg/node.py b/slither/core/cfg/node.py index 5ad1d4c43..a27259c86 100644 --- a/slither/core/cfg/node.py +++ b/slither/core/cfg/node.py @@ -800,11 +800,15 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met ################################################################################### @property - def phi_origins_local_variables(self,) -> Dict[str, Tuple[LocalVariable, Set["Node"]]]: + def phi_origins_local_variables( + self, + ) -> Dict[str, Tuple[LocalVariable, Set["Node"]]]: return self._phi_origins_local_variables @property - def phi_origins_state_variables(self,) -> Dict[str, Tuple[StateVariable, Set["Node"]]]: + def phi_origins_state_variables( + self, + ) -> Dict[str, Tuple[StateVariable, Set["Node"]]]: return self._phi_origins_state_variables # @property diff --git a/slither/core/declarations/function.py b/slither/core/declarations/function.py index 3f2e64dbb..f8d8c8158 100644 --- a/slither/core/declarations/function.py +++ b/slither/core/declarations/function.py @@ -51,7 +51,10 @@ ReacheableNode = namedtuple("ReacheableNode", ["node", "ir"]) class ModifierStatements: def __init__( - self, modifier: Union["Contract", "Function"], entry_point: "Node", nodes: List["Node"], + self, + modifier: Union["Contract", "Function"], + entry_point: "Node", + nodes: List["Node"], ): self._modifier = modifier self._entry_point = entry_point @@ -1147,7 +1150,9 @@ class Function(metaclass=ABCMeta): # pylint: disable=too-many-public-methods @staticmethod def _explore_func_conditional( - func: "Function", f: Callable[["Node"], List[SolidityVariable]], include_loop: bool, + func: "Function", + f: Callable[["Node"], List[SolidityVariable]], + include_loop: bool, ): ret = [f(n) for n in func.nodes if n.is_conditional(include_loop)] return [item for sublist in ret for item in sublist] @@ -1594,10 +1599,14 @@ class Function(metaclass=ABCMeta): # pylint: disable=too-many-public-methods return ret - def get_last_ssa_state_variables_instances(self,) -> Dict[str, Set["SlithIRVariable"]]: + def get_last_ssa_state_variables_instances( + self, + ) -> Dict[str, Set["SlithIRVariable"]]: return self._get_last_ssa_variable_instances(target_state=True, target_local=False) - def get_last_ssa_local_variables_instances(self,) -> Dict[str, Set["SlithIRVariable"]]: + def get_last_ssa_local_variables_instances( + self, + ) -> Dict[str, Set["SlithIRVariable"]]: return self._get_last_ssa_variable_instances(target_state=False, target_local=True) @staticmethod diff --git a/slither/core/solidity_types/function_type.py b/slither/core/solidity_types/function_type.py index 320488223..b1937db90 100644 --- a/slither/core/solidity_types/function_type.py +++ b/slither/core/solidity_types/function_type.py @@ -6,7 +6,9 @@ from slither.core.variables.function_type_variable import FunctionTypeVariable class FunctionType(Type): def __init__( - self, params: List[FunctionTypeVariable], return_values: List[FunctionTypeVariable], + self, + params: List[FunctionTypeVariable], + return_values: List[FunctionTypeVariable], ): assert all(isinstance(x, FunctionTypeVariable) for x in params) assert all(isinstance(x, FunctionTypeVariable) for x in return_values) diff --git a/slither/detectors/attributes/locked_ether.py b/slither/detectors/attributes/locked_ether.py index 96d155281..efcbcef8b 100644 --- a/slither/detectors/attributes/locked_ether.py +++ b/slither/detectors/attributes/locked_ether.py @@ -53,7 +53,8 @@ Every Ether sent to `Locked` will be lost.""" for node in function.nodes: for ir in node.irs: if isinstance( - ir, (Send, Transfer, HighLevelCall, LowLevelCall, NewContract), + ir, + (Send, Transfer, HighLevelCall, LowLevelCall, NewContract), ): if ir.call_value and ir.call_value != 0: return False diff --git a/slither/detectors/functions/arbitrary_send.py b/slither/detectors/functions/arbitrary_send.py index ac5422743..bb8a8d73e 100644 --- a/slither/detectors/functions/arbitrary_send.py +++ b/slither/detectors/functions/arbitrary_send.py @@ -41,7 +41,9 @@ def arbitrary_send(func): if ir.variable_right == SolidityVariableComposed("msg.sender"): return False if is_dependent( - ir.variable_right, SolidityVariableComposed("msg.sender"), func.contract, + ir.variable_right, + SolidityVariableComposed("msg.sender"), + func.contract, ): return False if isinstance(ir, (HighLevelCall, LowLevelCall, Transfer, Send)): @@ -54,7 +56,9 @@ def arbitrary_send(func): if ir.call_value == SolidityVariableComposed("msg.value"): continue if is_dependent( - ir.call_value, SolidityVariableComposed("msg.value"), func.contract, + ir.call_value, + SolidityVariableComposed("msg.value"), + func.contract, ): continue diff --git a/slither/detectors/naming_convention/naming_convention.py b/slither/detectors/naming_convention/naming_convention.py index 14cd4ea3f..656f913b3 100644 --- a/slither/detectors/naming_convention/naming_convention.py +++ b/slither/detectors/naming_convention/naming_convention.py @@ -86,10 +86,14 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 if func.is_constructor: continue if not self.is_mixed_case(func.name): - if func.visibility in [ - "internal", - "private", - ] and self.is_mixed_case_with_underscore(func.name): + if ( + func.visibility + in [ + "internal", + "private", + ] + and self.is_mixed_case_with_underscore(func.name) + ): continue if func.name.startswith("echidna_") or func.name.startswith("crytic_"): continue @@ -125,7 +129,11 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 res = self.generate_result(info) res.add( - var, {"target": "variable", "convention": "l_O_I_should_not_be_used",}, + var, + { + "target": "variable", + "convention": "l_O_I_should_not_be_used", + }, ) results.append(res) diff --git a/slither/detectors/operations/block_timestamp.py b/slither/detectors/operations/block_timestamp.py index 54d091d0d..01941257d 100644 --- a/slither/detectors/operations/block_timestamp.py +++ b/slither/detectors/operations/block_timestamp.py @@ -36,7 +36,9 @@ def _timestamp(func: Function) -> List[Node]: return sorted(list(ret), key=lambda x: x.node_id) -def _detect_dangerous_timestamp(contract: Contract,) -> List[Tuple[Function, List[Node]]]: +def _detect_dangerous_timestamp( + contract: Contract, +) -> List[Tuple[Function, List[Node]]]: """ Args: contract (Contract) diff --git a/slither/detectors/reentrancy/reentrancy.py b/slither/detectors/reentrancy/reentrancy.py index 3ab044757..94be2b243 100644 --- a/slither/detectors/reentrancy/reentrancy.py +++ b/slither/detectors/reentrancy/reentrancy.py @@ -127,7 +127,8 @@ class AbstractState: ) self._reads = union_dict(self._reads, father.context[detector.KEY].reads) self._reads_prior_calls = union_dict( - self.reads_prior_calls, father.context[detector.KEY].reads_prior_calls, + self.reads_prior_calls, + father.context[detector.KEY].reads_prior_calls, ) def analyze_node(self, node, detector): diff --git a/slither/detectors/reentrancy/reentrancy_benign.py b/slither/detectors/reentrancy/reentrancy_benign.py index 1894024c7..89cb0cee0 100644 --- a/slither/detectors/reentrancy/reentrancy_benign.py +++ b/slither/detectors/reentrancy/reentrancy_benign.py @@ -63,7 +63,11 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr if v in node.context[self.KEY].reads_prior_calls[c] ] not_read_then_written = { - FindingValue(v, node, tuple(sorted(nodes, key=lambda x: x.node_id)),) + FindingValue( + v, + node, + tuple(sorted(nodes, key=lambda x: x.node_id)), + ) for (v, nodes) in node.context[self.KEY].written.items() if v not in read_then_written } @@ -126,7 +130,8 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr for call_list_info in calls_list: if call_list_info != call_info: res.add( - call_list_info, {"underlying_type": "external_calls_sending_eth"}, + call_list_info, + {"underlying_type": "external_calls_sending_eth"}, ) # @@ -138,7 +143,8 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr for call_list_info in calls_list: if call_list_info != call_info: res.add( - call_list_info, {"underlying_type": "external_calls_sending_eth"}, + call_list_info, + {"underlying_type": "external_calls_sending_eth"}, ) # Add all variables written via nodes which write them. diff --git a/slither/detectors/reentrancy/reentrancy_eth.py b/slither/detectors/reentrancy/reentrancy_eth.py index 2173454b5..832e0d16b 100644 --- a/slither/detectors/reentrancy/reentrancy_eth.py +++ b/slither/detectors/reentrancy/reentrancy_eth.py @@ -63,7 +63,9 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m continue read_then_written |= { FindingValue( - v, node, tuple(sorted(nodes, key=lambda x: x.node_id)), + v, + node, + tuple(sorted(nodes, key=lambda x: x.node_id)), ) for (v, nodes) in node.context[self.KEY].written.items() if v in node.context[self.KEY].reads_prior_calls[c] @@ -128,7 +130,8 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m for call_list_info in calls_list: if call_list_info != call_info: res.add( - call_list_info, {"underlying_type": "external_calls_sending_eth"}, + call_list_info, + {"underlying_type": "external_calls_sending_eth"}, ) # If the calls are not the same ones that send eth, add the eth sending nodes. @@ -138,7 +141,8 @@ Bob uses the re-entrancy bug to call `withdrawBalance` two times, and withdraw m for call_list_info in calls_list: if call_list_info != call_info: res.add( - call_list_info, {"underlying_type": "external_calls_sending_eth"}, + call_list_info, + {"underlying_type": "external_calls_sending_eth"}, ) # Add all variables written via nodes which write them. diff --git a/slither/detectors/reentrancy/reentrancy_events.py b/slither/detectors/reentrancy/reentrancy_events.py index 5c0ba3e7c..b5d146c5d 100644 --- a/slither/detectors/reentrancy/reentrancy_events.py +++ b/slither/detectors/reentrancy/reentrancy_events.py @@ -61,7 +61,11 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w send_eth=to_hashable(node.context[self.KEY].send_eth), ) finding_vars = { - FindingValue(e, e.node, tuple(sorted(nodes, key=lambda x: x.node_id)),) + FindingValue( + e, + e.node, + tuple(sorted(nodes, key=lambda x: x.node_id)), + ) for (e, nodes) in node.context[self.KEY].events.items() } if finding_vars: @@ -115,7 +119,8 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w for call_list_info in calls_list: if call_list_info != call_info: res.add( - call_list_info, {"underlying_type": "external_calls_sending_eth"}, + call_list_info, + {"underlying_type": "external_calls_sending_eth"}, ) # @@ -127,7 +132,8 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w for call_list_info in calls_list: if call_list_info != call_info: res.add( - call_list_info, {"underlying_type": "external_calls_sending_eth"}, + call_list_info, + {"underlying_type": "external_calls_sending_eth"}, ) for finding_value in events: diff --git a/slither/detectors/reentrancy/reentrancy_no_gas.py b/slither/detectors/reentrancy/reentrancy_no_gas.py index 2e6386b3b..bc9a473c2 100644 --- a/slither/detectors/reentrancy/reentrancy_no_gas.py +++ b/slither/detectors/reentrancy/reentrancy_no_gas.py @@ -72,11 +72,19 @@ Only report reentrancy that is based on `transfer` or `send`.""" send_eth=to_hashable(node.context[self.KEY].send_eth), ) finding_vars = { - FindingValue(v, node, tuple(sorted(nodes, key=lambda x: x.node_id)),) + FindingValue( + v, + node, + tuple(sorted(nodes, key=lambda x: x.node_id)), + ) for (v, nodes) in node.context[self.KEY].written.items() } finding_vars |= { - FindingValue(e, e.node, tuple(sorted(nodes, key=lambda x: x.node_id)),) + FindingValue( + e, + e.node, + tuple(sorted(nodes, key=lambda x: x.node_id)), + ) for (e, nodes) in node.context[self.KEY].events.items() } if finding_vars: @@ -151,7 +159,8 @@ Only report reentrancy that is based on `transfer` or `send`.""" for call_list_info in calls_list: if call_list_info != call_info: res.add( - call_list_info, {"underlying_type": "external_calls_sending_eth"}, + call_list_info, + {"underlying_type": "external_calls_sending_eth"}, ) # @@ -163,7 +172,8 @@ Only report reentrancy that is based on `transfer` or `send`.""" for call_list_info in calls_list: if call_list_info != call_info: res.add( - call_list_info, {"underlying_type": "external_calls_sending_eth"}, + call_list_info, + {"underlying_type": "external_calls_sending_eth"}, ) # Add all variables written via nodes which write them. diff --git a/slither/detectors/reentrancy/reentrancy_read_before_write.py b/slither/detectors/reentrancy/reentrancy_read_before_write.py index a08e4f9b5..64f655c07 100644 --- a/slither/detectors/reentrancy/reentrancy_read_before_write.py +++ b/slither/detectors/reentrancy/reentrancy_read_before_write.py @@ -58,7 +58,9 @@ Do not report reentrancies that involve Ether (see `reentrancy-eth`).""" continue read_then_written |= { FindingValue( - v, node, tuple(sorted(nodes, key=lambda x: x.node_id)), + v, + node, + tuple(sorted(nodes, key=lambda x: x.node_id)), ) for (v, nodes) in node.context[self.KEY].written.items() if v in node.context[self.KEY].reads_prior_calls[c] @@ -114,7 +116,8 @@ Do not report reentrancies that involve Ether (see `reentrancy-eth`).""" for call_list_info in calls_list: if call_list_info != call_info: res.add( - call_list_info, {"underlying_type": "external_calls_sending_eth"}, + call_list_info, + {"underlying_type": "external_calls_sending_eth"}, ) # Add all variables written via nodes which write them. diff --git a/slither/detectors/statements/incorrect_strict_equality.py b/slither/detectors/statements/incorrect_strict_equality.py index bf8ce9118..d7a6bc91d 100644 --- a/slither/detectors/statements/incorrect_strict_equality.py +++ b/slither/detectors/statements/incorrect_strict_equality.py @@ -60,13 +60,13 @@ contract Crowdsale{ return isinstance(ir, Binary) and ir.type == BinaryType.EQUAL @staticmethod - def is_any_tainted(variables, taints, function): + def is_any_tainted(variables, taints, function) -> bool: return any( - [ + ( is_dependent_ssa(var, taint, function.contract) for var in variables for taint in taints - ] + ) ) def taint_balance_equalities(self, functions): diff --git a/slither/detectors/statements/unprotected_upgradeable.py b/slither/detectors/statements/unprotected_upgradeable.py index e5966a927..e3eb87369 100644 --- a/slither/detectors/statements/unprotected_upgradeable.py +++ b/slither/detectors/statements/unprotected_upgradeable.py @@ -79,7 +79,9 @@ class UnprotectedUpgradeable(AbstractDetector): " is an upgradeable contract that does not protect its initiliaze functions: ", ] + initiliaze_functions - + [". Anyone can delete the contract with: ",] + + [ + ". Anyone can delete the contract with: ", + ] + functions_that_can_destroy ) diff --git a/slither/formatters/attributes/constant_pragma.py b/slither/formatters/attributes/constant_pragma.py index 7a424d74d..8cb35b81e 100644 --- a/slither/formatters/attributes/constant_pragma.py +++ b/slither/formatters/attributes/constant_pragma.py @@ -70,5 +70,10 @@ def _patch( in_file_str = slither.source_code[in_file].encode("utf8") old_str_of_interest = in_file_str[modify_loc_start:modify_loc_end] create_patch( - result, in_file, int(modify_loc_start), int(modify_loc_end), old_str_of_interest, pragma, + result, + in_file, + int(modify_loc_start), + int(modify_loc_end), + old_str_of_interest, + pragma, ) diff --git a/slither/formatters/naming_convention/naming_convention.py b/slither/formatters/naming_convention/naming_convention.py index 27a4349cd..ccf1ba037 100644 --- a/slither/formatters/naming_convention/naming_convention.py +++ b/slither/formatters/naming_convention/naming_convention.py @@ -575,7 +575,12 @@ def _explore_irs(slither, irs, result, target, convert): loc_end = loc_start + len(old_str) create_patch( - result, filename_source_code, loc_start, loc_end, old_str, new_str, + result, + filename_source_code, + loc_start, + loc_end, + old_str, + new_str, ) diff --git a/slither/printers/call/call_graph.py b/slither/printers/call/call_graph.py index 9e348b8e6..c74ece8fa 100644 --- a/slither/printers/call/call_graph.py +++ b/slither/printers/call/call_graph.py @@ -33,21 +33,39 @@ def _edge(from_node, to_node): # return dot language string to add graph node (with optional label) def _node(node, label=None): - return " ".join((f'"{node}"', f'[label="{label}"]' if label is not None else "",)) + return " ".join( + ( + f'"{node}"', + f'[label="{label}"]' if label is not None else "", + ) + ) # pylint: disable=too-many-arguments def _process_internal_call( - contract, function, internal_call, contract_calls, solidity_functions, solidity_calls, + contract, + function, + internal_call, + contract_calls, + solidity_functions, + solidity_calls, ): if isinstance(internal_call, (Function)): contract_calls[contract].add( - _edge(_function_node(contract, function), _function_node(contract, internal_call),) + _edge( + _function_node(contract, function), + _function_node(contract, internal_call), + ) ) elif isinstance(internal_call, (SolidityFunction)): - solidity_functions.add(_node(_solidity_function_node(internal_call)),) + solidity_functions.add( + _node(_solidity_function_node(internal_call)), + ) solidity_calls.add( - _edge(_function_node(contract, function), _solidity_function_node(internal_call),) + _edge( + _function_node(contract, function), + _solidity_function_node(internal_call), + ) ) @@ -84,7 +102,12 @@ def _render_solidity_calls(solidity_functions, solidity_calls): def _process_external_call( - contract, function, external_call, contract_functions, external_calls, all_contracts, + contract, + function, + external_call, + contract_functions, + external_calls, + all_contracts, ): external_contract, external_function = external_call @@ -94,7 +117,10 @@ def _process_external_call( # add variable as node to respective contract if isinstance(external_function, (Variable)): contract_functions[external_contract].add( - _node(_function_node(external_contract, external_function), external_function.name,) + _node( + _function_node(external_contract, external_function), + external_function.name, + ) ) external_calls.add( @@ -116,15 +142,27 @@ def _process_function( external_calls, all_contracts, ): - contract_functions[contract].add(_node(_function_node(contract, function), function.name),) + contract_functions[contract].add( + _node(_function_node(contract, function), function.name), + ) for internal_call in function.internal_calls: _process_internal_call( - contract, function, internal_call, contract_calls, solidity_functions, solidity_calls, + contract, + function, + internal_call, + contract_calls, + solidity_functions, + solidity_calls, ) for external_call in function.high_level_calls: _process_external_call( - contract, function, external_call, contract_functions, external_calls, all_contracts, + contract, + function, + external_call, + contract_functions, + external_calls, + all_contracts, ) diff --git a/slither/printers/functions/authorization.py b/slither/printers/functions/authorization.py index 0ae2ae8b3..522c5d996 100644 --- a/slither/printers/functions/authorization.py +++ b/slither/printers/functions/authorization.py @@ -52,7 +52,11 @@ class PrinterWrittenVariablesAndAuthorization(AbstractPrinter): state_variables_written = [v.name for v in function.all_state_variables_written()] msg_sender_condition = self.get_msg_sender_checks(function) table.add_row( - [function.name, str(state_variables_written), str(msg_sender_condition),] + [ + function.name, + str(state_variables_written), + str(msg_sender_condition), + ] ) all_tables.append((contract.name, table)) txt += str(table) + "\n" diff --git a/slither/printers/summary/evm.py b/slither/printers/summary/evm.py index 365f6a626..e14365062 100644 --- a/slither/printers/summary/evm.py +++ b/slither/printers/summary/evm.py @@ -101,7 +101,8 @@ class PrinterEVM(AbstractPrinter): ) txt += green( "\t\tSource line {}: {}\n".format( - node_source_line, contract_file_lines[node_source_line - 1].rstrip(), + node_source_line, + contract_file_lines[node_source_line - 1].rstrip(), ) ) txt += magenta("\t\tEVM Instructions:\n") @@ -123,7 +124,8 @@ class PrinterEVM(AbstractPrinter): ) txt += green( "\t\tSource line {}: {}\n".format( - node_source_line, contract_file_lines[node_source_line - 1].rstrip(), + node_source_line, + contract_file_lines[node_source_line - 1].rstrip(), ) ) txt += magenta("\t\tEVM Instructions:\n") diff --git a/slither/printers/summary/function.py b/slither/printers/summary/function.py index a711e9291..82844159b 100644 --- a/slither/printers/summary/function.py +++ b/slither/printers/summary/function.py @@ -65,11 +65,26 @@ class FunctionSummary(AbstractPrinter): internal_calls = self._convert(internal_calls) external_calls = self._convert(external_calls) table.add_row( - [f_name, visi, modifiers, read, write, internal_calls, external_calls,] + [ + f_name, + visi, + modifiers, + read, + write, + internal_calls, + external_calls, + ] ) txt += "\n \n" + str(table) table = MyPrettyTable( - ["Modifiers", "Visibility", "Read", "Write", "Internal Calls", "External Calls",] + [ + "Modifiers", + "Visibility", + "Read", + "Write", + "Internal Calls", + "External Calls", + ] ) for ( _c_name, diff --git a/slither/printers/summary/human_summary.py b/slither/printers/summary/human_summary.py index 713472386..b47c51ddc 100644 --- a/slither/printers/summary/human_summary.py +++ b/slither/printers/summary/human_summary.py @@ -379,7 +379,14 @@ class PrinterHumanSummary(AbstractPrinter): ) table.add_row( - [contract.name, number_functions, ercs, erc20_info, is_complex, features,] + [ + contract.name, + number_functions, + ercs, + erc20_info, + is_complex, + features, + ] ) self.info(txt + "\n" + str(table)) diff --git a/slither/printers/summary/require_calls.py b/slither/printers/summary/require_calls.py index 49b9e0d29..5f455985f 100644 --- a/slither/printers/summary/require_calls.py +++ b/slither/printers/summary/require_calls.py @@ -46,7 +46,10 @@ class RequireOrAssert(AbstractPrinter): ] require = [ir.node for ir in require] table.add_row( - [function.name, self._convert([str(m.expression) for m in set(require)]),] + [ + function.name, + self._convert([str(m.expression) for m in set(require)]), + ] ) txt += "\n" + str(table) self.info(txt) diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index c3e366f8a..bf88f54f5 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -210,7 +210,8 @@ def convert_arguments(arguments): def is_temporary(ins): return isinstance( - ins, (Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure), + ins, + (Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure), ) @@ -625,7 +626,8 @@ def propagate_types(ir, node: "Node"): # pylint: disable=too-many-locals # We dont need to check for function collision, as solc prevents the use of selector # if there are multiple functions with the same name f = next( - (f for f in type_t.functions if f.name == ir.variable_right), None, + (f for f in type_t.functions if f.name == ir.variable_right), + None, ) if f: ir.lvalue.set_type(f) @@ -836,7 +838,10 @@ def extract_tmp_call(ins, contract): # pylint: disable=too-many-locals ins.called = SolidityFunction("blockhash(uint256)") elif str(ins.called) == "this.balance": s = SolidityCall( - SolidityFunction("this.balance()"), ins.nbr_arguments, ins.lvalue, ins.type_call, + SolidityFunction("this.balance()"), + ins.nbr_arguments, + ins.lvalue, + ins.type_call, ) s.set_expression(ins.expression) return s @@ -1154,7 +1159,11 @@ def look_for_library(contract, ir, using_for, t): lib_contract = contract.slither.get_contract_from_name(str(destination)) if lib_contract: lib_call = LibraryCall( - lib_contract, ir.function_name, ir.nbr_arguments, ir.lvalue, ir.type_call, + lib_contract, + ir.function_name, + ir.nbr_arguments, + ir.lvalue, + ir.type_call, ) lib_call.set_expression(ir.expression) lib_call.set_node(ir.node) @@ -1387,7 +1396,14 @@ def remove_temporary(result): ins for ins in result if not isinstance( - ins, (Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure,), + ins, + ( + Argument, + TmpNewElementaryType, + TmpNewContract, + TmpNewArray, + TmpNewStructure, + ), ) ] diff --git a/slither/slithir/operations/binary.py b/slither/slithir/operations/binary.py index 334a6a354..25535ea9c 100644 --- a/slither/slithir/operations/binary.py +++ b/slither/slithir/operations/binary.py @@ -175,7 +175,11 @@ class Binary(OperationWithLValue): while isinstance(points, ReferenceVariable): points = points.points_to return "{}(-> {}) = {} {} {}".format( - str(self.lvalue), points, self.variable_left, self.type_str, self.variable_right, + str(self.lvalue), + points, + self.variable_left, + self.type_str, + self.variable_right, ) return "{}({}) = {} {} {}".format( str(self.lvalue), diff --git a/slither/slithir/operations/library_call.py b/slither/slithir/operations/library_call.py index 682a0d4c6..d7c89a4de 100644 --- a/slither/slithir/operations/library_call.py +++ b/slither/slithir/operations/library_call.py @@ -38,5 +38,9 @@ class LibraryCall(HighLevelCall): lvalue = "{}({}) = ".format(self.lvalue, self.lvalue.type) txt = "{}LIBRARY_CALL, dest:{}, function:{}, arguments:{} {}" return txt.format( - lvalue, self.destination, self.function_name, [str(x) for x in arguments], gas, + lvalue, + self.destination, + self.function_name, + [str(x) for x in arguments], + gas, ) diff --git a/slither/slithir/tmp_operations/tmp_call.py b/slither/slithir/tmp_operations/tmp_call.py index 4abeea01a..2157d0323 100644 --- a/slither/slithir/tmp_operations/tmp_call.py +++ b/slither/slithir/tmp_operations/tmp_call.py @@ -13,7 +13,14 @@ class TmpCall(OperationWithLValue): # pylint: disable=too-many-instance-attribu def __init__(self, called, nbr_arguments, result, type_call): assert isinstance( called, - (Contract, Variable, SolidityVariableComposed, SolidityFunction, Structure, Event,), + ( + Contract, + Variable, + SolidityVariableComposed, + SolidityFunction, + Structure, + Event, + ), ) super().__init__() self._called = called diff --git a/slither/slithir/utils/ssa.py b/slither/slithir/utils/ssa.py index 1d62c3822..5b21e123e 100644 --- a/slither/slithir/utils/ssa.py +++ b/slither/slithir/utils/ssa.py @@ -173,7 +173,9 @@ def add_ssa_ir(function, all_state_variables_instances): init_state_variables_instances = dict(all_state_variables_instances) initiate_all_local_variables_instances( - function.nodes, init_local_variables_instances, all_init_local_variables_instances, + function.nodes, + init_local_variables_instances, + all_init_local_variables_instances, ) generate_ssa_irs( @@ -506,7 +508,8 @@ def add_phi_origins(node, local_variables_definition, state_variables_definition # We keep the instance as we want to avoid to add __hash__ on v.name in Variable # That might work for this used, but could create collision for other uses local_variables_definition = dict( - local_variables_definition, **{v.name: (v, node) for v in node.local_variables_written}, + local_variables_definition, + **{v.name: (v, node) for v in node.local_variables_written}, ) state_variables_definition = dict( state_variables_definition, @@ -598,7 +601,16 @@ def get( return tuple_variables_instances[variable.index] assert isinstance( variable, - (Constant, SolidityVariable, Contract, Enum, SolidityFunction, Structure, Function, Type,), + ( + Constant, + SolidityVariable, + Contract, + Enum, + SolidityFunction, + Structure, + Function, + Type, + ), ) # type for abi.decode(.., t) return variable diff --git a/slither/slithir/utils/utils.py b/slither/slithir/utils/utils.py index d6cca249f..796bb822c 100644 --- a/slither/slithir/utils/utils.py +++ b/slither/slithir/utils/utils.py @@ -25,5 +25,12 @@ def is_valid_rvalue(v): def is_valid_lvalue(v): return isinstance( - v, (StateVariable, LocalVariable, TemporaryVariable, ReferenceVariable, TupleVariable,), + v, + ( + StateVariable, + LocalVariable, + TemporaryVariable, + ReferenceVariable, + TupleVariable, + ), ) diff --git a/slither/solc_parsing/declarations/contract.py b/slither/solc_parsing/declarations/contract.py index 300d29bfe..54067b8fe 100644 --- a/slither/solc_parsing/declarations/contract.py +++ b/slither/solc_parsing/declarations/contract.py @@ -411,7 +411,8 @@ class ContractSolc: assert isinstance(underlying_function, FunctionContract) elem.set_contract_declarer(underlying_function.contract_declarer) elem.set_offset( - element_parser.function_not_parsed["src"], self._contract.slither, + element_parser.function_not_parsed["src"], + self._contract.slither, ) elem_parser = Cls_parser( diff --git a/slither/solc_parsing/declarations/function.py b/slither/solc_parsing/declarations/function.py index d12a6ce88..e437bdda3 100644 --- a/slither/solc_parsing/declarations/function.py +++ b/slither/solc_parsing/declarations/function.py @@ -454,7 +454,10 @@ class FunctionSolc: return key in attributes and not attributes[key] if attributes and any( - map(has_hint, ["condition", "initializationExpression", "loopExpression"],) + map( + has_hint, + ["condition", "initializationExpression", "loopExpression"], + ) ): # if we have attribute hints, rely on those @@ -602,7 +605,8 @@ class FunctionSolc: link_underlying_nodes(node_startDoWhile, node_condition) else: link_nodes( - node_startDoWhile.underlying_node, node_condition.underlying_node.sons[0], + node_startDoWhile.underlying_node, + node_condition.underlying_node.sons[0], ) link_underlying_nodes(statement, node_condition) link_underlying_nodes(node_condition, node_endDoWhile) diff --git a/slither/solc_parsing/declarations/structure_contract.py b/slither/solc_parsing/declarations/structure_contract.py index ac3e5982d..1fea022c6 100644 --- a/slither/solc_parsing/declarations/structure_contract.py +++ b/slither/solc_parsing/declarations/structure_contract.py @@ -19,7 +19,10 @@ class StructureContractSolc: # pylint: disable=too-few-public-methods # elems = [(type, name)] def __init__( # pylint: disable=too-many-arguments - self, st: Structure, struct: Dict, contract_parser: "ContractSolc", + self, + st: Structure, + struct: Dict, + contract_parser: "ContractSolc", ): if contract_parser.is_compact_ast: diff --git a/slither/solc_parsing/declarations/structure_top_level.py b/slither/solc_parsing/declarations/structure_top_level.py index 23108d603..fb26426d4 100644 --- a/slither/solc_parsing/declarations/structure_top_level.py +++ b/slither/solc_parsing/declarations/structure_top_level.py @@ -19,7 +19,10 @@ class StructureTopLevelSolc: # pylint: disable=too-few-public-methods # elems = [(type, name)] def __init__( # pylint: disable=too-many-arguments - self, st: Structure, struct: Dict, slither_parser: "SlitherSolc", + self, + st: Structure, + struct: Dict, + slither_parser: "SlitherSolc", ): if slither_parser.is_compact_ast: diff --git a/slither/solc_parsing/expressions/expression_parsing.py b/slither/solc_parsing/expressions/expression_parsing.py index f4cbdbc2d..4a3f5109f 100644 --- a/slither/solc_parsing/expressions/expression_parsing.py +++ b/slither/solc_parsing/expressions/expression_parsing.py @@ -269,7 +269,14 @@ def find_variable( referenced_declaration: Optional[int] = None, is_super=False, ) -> Union[ - Variable, Function, Contract, SolidityVariable, SolidityFunction, Event, Enum, Structure, + Variable, + Function, + Contract, + SolidityVariable, + SolidityFunction, + Event, + Enum, + Structure, ]: from slither.solc_parsing.declarations.function import FunctionSolc from slither.solc_parsing.declarations.contract import ContractSolc @@ -312,9 +319,9 @@ def find_variable( if ret: return ret - function_parser: Optional[FunctionSolc] = caller_context if isinstance( - caller_context, FunctionSolc - ) else None + function_parser: Optional[FunctionSolc] = ( + caller_context if isinstance(caller_context, FunctionSolc) else None + ) ret = _find_variable_in_function_parser(var_name, function_parser, referenced_declaration) if ret: return ret diff --git a/slither/solc_parsing/slitherSolc.py b/slither/solc_parsing/slitherSolc.py index 1e7a62485..e4638e974 100644 --- a/slither/solc_parsing/slitherSolc.py +++ b/slither/solc_parsing/slitherSolc.py @@ -410,7 +410,9 @@ Please rename it, this name is reserved for Slither's internals""" contracts_to_be_analyzed += [contract] def _analyze_first_part( - self, contracts_to_be_analyzed: List[ContractSolc], libraries: List[ContractSolc], + self, + contracts_to_be_analyzed: List[ContractSolc], + libraries: List[ContractSolc], ): for lib in libraries: self._parse_struct_var_modifiers_functions(lib) @@ -435,7 +437,9 @@ Please rename it, this name is reserved for Slither's internals""" contracts_to_be_analyzed += [contract] def _analyze_second_part( - self, contracts_to_be_analyzed: List[ContractSolc], libraries: List[ContractSolc], + self, + contracts_to_be_analyzed: List[ContractSolc], + libraries: List[ContractSolc], ): for lib in libraries: self._analyze_struct_events(lib) @@ -462,7 +466,9 @@ Please rename it, this name is reserved for Slither's internals""" contracts_to_be_analyzed += [contract] def _analyze_third_part( - self, contracts_to_be_analyzed: List[ContractSolc], libraries: List[ContractSolc], + self, + contracts_to_be_analyzed: List[ContractSolc], + libraries: List[ContractSolc], ): for lib in libraries: self._analyze_variables_modifiers_functions(lib) diff --git a/slither/solc_parsing/solidity_types/type_parsing.py b/slither/solc_parsing/solidity_types/type_parsing.py index dbb276e1f..0604b4a70 100644 --- a/slither/solc_parsing/solidity_types/type_parsing.py +++ b/slither/solc_parsing/solidity_types/type_parsing.py @@ -155,7 +155,8 @@ def _find_from_type_name( # pylint: disable=too-many-locals,too-many-branches,t found = re.findall("mapping\(([a-zA-Z0-9\.]*) => ([ a-zA-Z0-9\.\[\]]*)\)", name) else: found = re.findall( - "mapping\(([a-zA-Z0-9\.]*) => (mapping\([=> a-zA-Z0-9\.\[\]]*\))\)", name, + "mapping\(([a-zA-Z0-9\.]*) => (mapping\([=> a-zA-Z0-9\.\[\]]*\))\)", + name, ) assert len(found) == 1 from_ = found[0][0] diff --git a/slither/solc_parsing/yul/parse_yul.py b/slither/solc_parsing/yul/parse_yul.py index a7a427712..e3fae77f0 100644 --- a/slither/solc_parsing/yul/parse_yul.py +++ b/slither/solc_parsing/yul/parse_yul.py @@ -165,7 +165,10 @@ class YulScope(metaclass=abc.ABCMeta): self._yul_local_functions.append(func) def get_yul_local_function_from_name(self, func_name): - return next((v for v in self._yul_local_functions if v.underlying.name == func_name), None,) + return next( + (v for v in self._yul_local_functions if v.underlying.name == func_name), + None, + ) class YulLocalVariable: # pylint: disable=too-few-public-methods @@ -457,7 +460,11 @@ def convert_yul_switch(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: "name": "eq", }, "arguments": [ - {"nodeType": "YulIdentifier", "src": case_ast["src"], "name": switch_expr_var,}, + { + "nodeType": "YulIdentifier", + "src": case_ast["src"], + "name": switch_expr_var, + }, value_ast, ], }, diff --git a/slither/tools/erc_conformance/__main__.py b/slither/tools/erc_conformance/__main__.py index ac5aeba3a..9eb977ff6 100644 --- a/slither/tools/erc_conformance/__main__.py +++ b/slither/tools/erc_conformance/__main__.py @@ -31,7 +31,8 @@ def parse_args(): :return: Returns the arguments for the program. """ parser = argparse.ArgumentParser( - description="Check the ERC 20 conformance", usage="slither-check-erc project contractName", + description="Check the ERC 20 conformance", + usage="slither-check-erc project contractName", ) parser.add_argument("project", help="The codebase to be tested.") diff --git a/slither/tools/flattening/__main__.py b/slither/tools/flattening/__main__.py index aac9b86c0..308dd8106 100644 --- a/slither/tools/flattening/__main__.py +++ b/slither/tools/flattening/__main__.py @@ -41,7 +41,9 @@ def parse_args(): group_export = parser.add_argument_group("Export options") group_export.add_argument( - "--dir", help=f"Export directory (default: {DEFAULT_EXPORT_PATH}).", default=None, + "--dir", + help=f"Export directory (default: {DEFAULT_EXPORT_PATH}).", + default=None, ) group_export.add_argument( @@ -52,7 +54,10 @@ def parse_args(): ) parser.add_argument( - "--zip", help="Export all the files to a zip file", action="store", default=None, + "--zip", + help="Export all the files to a zip file", + action="store", + default=None, ) parser.add_argument( @@ -69,7 +74,9 @@ def parse_args(): ) group_patching.add_argument( - "--convert-private", help="Convert private variables to internal.", action="store_true", + "--convert-private", + help="Convert private variables to internal.", + action="store_true", ) group_patching.add_argument( diff --git a/slither/tools/flattening/export/export.py b/slither/tools/flattening/export/export.py index 2262a8dbb..75b9ac941 100644 --- a/slither/tools/flattening/export/export.py +++ b/slither/tools/flattening/export/export.py @@ -24,7 +24,9 @@ def save_to_zip(files: List[Export], zip_filename: str, zip_type: str = "lzma"): """ logger.info(f"Export {zip_filename}") with zipfile.ZipFile( - zip_filename, "w", compression=ZIP_TYPES_ACCEPTED.get(zip_type, zipfile.ZIP_LZMA), + zip_filename, + "w", + compression=ZIP_TYPES_ACCEPTED.get(zip_type, zipfile.ZIP_LZMA), ) as file_desc: for f in files: file_desc.writestr(str(f.filename), f.content) diff --git a/slither/tools/flattening/flattening.py b/slither/tools/flattening/flattening.py index c480d2e52..7790f9af1 100644 --- a/slither/tools/flattening/flattening.py +++ b/slither/tools/flattening/flattening.py @@ -108,7 +108,10 @@ class Flattening: regex = re.search(r"((\sexternal)\s+)|(\sexternal)$|(\)external)$", attributes) if regex: to_patch.append( - Patch(attributes_start + regex.span()[0] + 1, "public_to_external",) + Patch( + attributes_start + regex.span()[0] + 1, + "public_to_external", + ) ) else: raise SlitherException(f"External keyword not found {f.name} {attributes}") @@ -119,7 +122,10 @@ class Flattening: calldata_end = calldata_start + var.source_mapping["length"] calldata_idx = content[calldata_start:calldata_end].find(" calldata ") to_patch.append( - Patch(calldata_start + calldata_idx + 1, "calldata_to_memory",) + Patch( + calldata_start + calldata_idx + 1, + "calldata_to_memory", + ) ) if self._private_to_internal: @@ -133,7 +139,10 @@ class Flattening: regex = re.search(r" private ", attributes) if regex: to_patch.append( - Patch(attributes_start + regex.span()[0] + 1, "private_to_internal",) + Patch( + attributes_start + regex.span()[0] + 1, + "private_to_internal", + ) ) else: raise SlitherException( diff --git a/slither/tools/kspec_coverage/__main__.py b/slither/tools/kspec_coverage/__main__.py index 0b1e55f51..b6ce0f81b 100644 --- a/slither/tools/kspec_coverage/__main__.py +++ b/slither/tools/kspec_coverage/__main__.py @@ -22,18 +22,23 @@ def parse_args(): :return: Returns the arguments for the program. """ parser = argparse.ArgumentParser( - description="slither-kspec-coverage", usage="slither-kspec-coverage contract.sol kspec.md", + description="slither-kspec-coverage", + usage="slither-kspec-coverage contract.sol kspec.md", ) parser.add_argument( "contract", help="The filename of the contract or truffle directory to analyze." ) parser.add_argument( - "kspec", help="The filename of the Klab spec markdown for the analyzed contract(s)", + "kspec", + help="The filename of the Klab spec markdown for the analyzed contract(s)", ) parser.add_argument( - "--version", help="displays the current version", version="0.1.0", action="version", + "--version", + help="displays the current version", + version="0.1.0", + action="version", ) parser.add_argument( "--json", diff --git a/slither/tools/possible_paths/__main__.py b/slither/tools/possible_paths/__main__.py index ffa4f00af..e6940fcab 100644 --- a/slither/tools/possible_paths/__main__.py +++ b/slither/tools/possible_paths/__main__.py @@ -21,7 +21,8 @@ def parse_args(): :return: Returns the arguments for the program. """ parser = argparse.ArgumentParser( - description="PossiblePaths", usage="possible_paths.py filename [contract.function targets]", + description="PossiblePaths", + usage="possible_paths.py filename [contract.function targets]", ) parser.add_argument( diff --git a/slither/tools/possible_paths/possible_paths.py b/slither/tools/possible_paths/possible_paths.py index 72e6ba2d3..75ab29de4 100644 --- a/slither/tools/possible_paths/possible_paths.py +++ b/slither/tools/possible_paths/possible_paths.py @@ -18,7 +18,8 @@ def resolve_function(slither, contract_name, function_name): # Obtain the target function target_function = next( - (function for function in contract.functions if function.name == function_name), None, + (function for function in contract.functions if function.name == function_name), + None, ) # Verify we have resolved the function specified. diff --git a/slither/tools/properties/__main__.py b/slither/tools/properties/__main__.py index 594c58a79..4a2dc8c99 100644 --- a/slither/tools/properties/__main__.py +++ b/slither/tools/properties/__main__.py @@ -105,7 +105,9 @@ def parse_args(): ) parser.add_argument( - "--address-attacker", help=f"Attacker address. Default {ATTACKER_ADDRESS}", default=None, + "--address-attacker", + help=f"Attacker address. Default {ATTACKER_ADDRESS}", + default=None, ) # Add default arguments from crytic-compile diff --git a/slither/tools/properties/properties/erc20.py b/slither/tools/properties/properties/erc20.py index fce92346a..600c0b79c 100644 --- a/slither/tools/properties/properties/erc20.py +++ b/slither/tools/properties/properties/erc20.py @@ -107,7 +107,11 @@ def generate_erc20( # Generate the Test contract initialization_recommendation = _initialization_recommendation(type_property) contract_filename, contract_name = generate_test_contract( - contract, type_property, output_dir, property_file, initialization_recommendation, + contract, + type_property, + output_dir, + property_file, + initialization_recommendation, ) # Generate Echidna config file diff --git a/slither/tools/properties/properties/ercs/erc20/unit_tests/truffle.py b/slither/tools/properties/properties/ercs/erc20/unit_tests/truffle.py index 40fa30b61..58ac93d56 100644 --- a/slither/tools/properties/properties/ercs/erc20/unit_tests/truffle.py +++ b/slither/tools/properties/properties/ercs/erc20/unit_tests/truffle.py @@ -15,7 +15,10 @@ logger = logging.getLogger("Slither") def generate_truffle_test( - contract: Contract, type_property: str, unit_tests: List[Property], addresses: Addresses, + contract: Contract, + type_property: str, + unit_tests: List[Property], + addresses: Addresses, ) -> str: test_contract = f"Test{contract.name}{type_property}" filename_init = f"Initialization{test_contract}.js" @@ -35,7 +38,11 @@ def generate_truffle_test( ) generate_unit_test( - test_contract, filename, unit_tests, output_dir, addresses, + test_contract, + filename, + unit_tests, + output_dir, + addresses, ) log_info = "\n" diff --git a/slither/tools/similarity/__main__.py b/slither/tools/similarity/__main__.py index 9d75c563e..f7b2692ad 100755 --- a/slither/tools/similarity/__main__.py +++ b/slither/tools/similarity/__main__.py @@ -54,7 +54,10 @@ def parse_args(): ) parser.add_argument( - "--version", help="displays the current version", version="0.0", action="version", + "--version", + help="displays the current version", + version="0.0", + action="version", ) cryticparser.init(parser) diff --git a/slither/tools/slither_format/__main__.py b/slither/tools/slither_format/__main__.py index 007741bea..4c9bcab5e 100644 --- a/slither/tools/slither_format/__main__.py +++ b/slither/tools/slither_format/__main__.py @@ -41,10 +41,17 @@ def parse_args(): default=False, ) parser.add_argument( - "--verbose-json", "-j", help="verbose json output", action="store_true", default=False, + "--verbose-json", + "-j", + help="verbose json output", + action="store_true", + default=False, ) parser.add_argument( - "--version", help="displays the current version", version="0.1.0", action="version", + "--version", + help="displays the current version", + version="0.1.0", + action="version", ) parser.add_argument( diff --git a/slither/tools/slither_format/slither_format.py b/slither/tools/slither_format/slither_format.py index e6a4564ee..63ceb2a43 100644 --- a/slither/tools/slither_format/slither_format.py +++ b/slither/tools/slither_format/slither_format.py @@ -65,7 +65,10 @@ def slither_format(slither, **kwargs): # pylint: disable=too-many-locals logger.info(f"Issue: {one_line_description}") logger.info(f"Generated: ({export_result})") - for (_, diff,) in result["patches_diff"].items(): + for ( + _, + diff, + ) in result["patches_diff"].items(): filename = f"fix_{counter}.patch" path = Path(export_result, filename) logger.info(f"\t- {filename}") diff --git a/slither/tools/upgradeability/__main__.py b/slither/tools/upgradeability/__main__.py index bdf08a797..5bcc23ca1 100644 --- a/slither/tools/upgradeability/__main__.py +++ b/slither/tools/upgradeability/__main__.py @@ -57,7 +57,10 @@ def parse_args(): ) parser.add_argument( - "--markdown-root", help="URL for markdown generation", action="store", default="", + "--markdown-root", + help="URL for markdown generation", + action="store", + default="", ) parser.add_argument( diff --git a/slither/utils/erc.py b/slither/utils/erc.py index f45e60a76..87082bf12 100644 --- a/slither/utils/erc.py +++ b/slither/utils/erc.py @@ -63,7 +63,14 @@ ERC223 = [ ERC("totalSupply", [], "uint256", True, True, []), ERC("balanceOf", ["address"], "uint256", True, True, []), ERC("transfer", ["address", "uint256"], "bool", False, True, [ERC223_transfer_event]), - ERC("transfer", ["address", "uint256", "bytes"], "bool", False, True, [ERC223_transfer_event],), + ERC( + "transfer", + ["address", "uint256", "bytes"], + "bool", + False, + True, + [ERC223_transfer_event], + ), ERC( "transfer", ["address", "uint256", "bytes", "string"], @@ -118,10 +125,22 @@ ERC721 = [ [ERC721_transfer_event], ), ERC( - "transferFrom", ["address", "address", "uint256"], "", False, True, [ERC721_transfer_event], + "transferFrom", + ["address", "address", "uint256"], + "", + False, + True, + [ERC721_transfer_event], ), ERC("approve", ["address", "uint256"], "", False, True, [ERC721_approval_event]), - ERC("setApprovalForAll", ["address", "bool"], "", False, True, [ERC721_approvalforall_event],), + ERC( + "setApprovalForAll", + ["address", "bool"], + "", + False, + True, + [ERC721_approvalforall_event], + ), ERC("getApproved", ["uint256"], "address", True, True, []), ERC("isApprovedForAll", ["address", "address"], "bool", True, True, []), ] + ERC165 @@ -140,7 +159,14 @@ ERC721_signatures = erc_to_signatures(ERC721) # https://eips.ethereum.org/EIPS/eip-1820 ERC1820_EVENTS: List = [] ERC1820 = [ - ERC("canImplementInterfaceForAddress", ["bytes32", "address"], "bytes32", True, True, [],) + ERC( + "canImplementInterfaceForAddress", + ["bytes32", "address"], + "bytes32", + True, + True, + [], + ) ] ERC1820_signatures = erc_to_signatures(ERC1820) @@ -181,7 +207,14 @@ ERC777 = [ ERC("granularity", [], "uint256", True, True, []), ERC("defaultOperators", [], "address[]", True, True, []), ERC("isOperatorFor", ["address", "address"], "bool", True, True, []), - ERC("authorizeOperator", ["address"], "", False, True, [ERC777_authorizedOperator_event],), + ERC( + "authorizeOperator", + ["address"], + "", + False, + True, + [ERC777_authorizedOperator_event], + ), ERC("revokeOperator", ["address"], "", False, True, [ERC777_revokedoperator_event]), ERC("send", ["address", "uint256", "bytes"], "", False, True, [ERC777_sent_event]), ERC( diff --git a/slither/utils/expression_manipulations.py b/slither/utils/expression_manipulations.py index 2096ec9eb..915eb5306 100644 --- a/slither/utils/expression_manipulations.py +++ b/slither/utils/expression_manipulations.py @@ -110,21 +110,27 @@ class SplitTernaryExpression: if self.apply_copy(next_expr, true_expression, false_expression, f_call): # always on last arguments added self.copy_expression( - next_expr, true_expression.arguments[-1], false_expression.arguments[-1], + next_expr, + true_expression.arguments[-1], + false_expression.arguments[-1], ) elif isinstance(expression, TypeConversion): next_expr = expression.expression if self.apply_copy(next_expr, true_expression, false_expression, f_expression): self.copy_expression( - expression.expression, true_expression.expression, false_expression.expression, + expression.expression, + true_expression.expression, + false_expression.expression, ) elif isinstance(expression, UnaryOperation): next_expr = expression.expression if self.apply_copy(next_expr, true_expression, false_expression, f_expression): self.copy_expression( - expression.expression, true_expression.expression, false_expression.expression, + expression.expression, + true_expression.expression, + false_expression.expression, ) else: diff --git a/slither/utils/inheritance_analysis.py b/slither/utils/inheritance_analysis.py index 00cbfb1f0..66b9e8ac3 100644 --- a/slither/utils/inheritance_analysis.py +++ b/slither/utils/inheritance_analysis.py @@ -10,7 +10,9 @@ if TYPE_CHECKING: from slither.core.variables.state_variable import StateVariable -def detect_c3_function_shadowing(contract: "Contract",) -> Dict["Function", Set["Function"]]: +def detect_c3_function_shadowing( + contract: "Contract", +) -> Dict["Function", Set["Function"]]: """ Detects and obtains functions which are indirectly shadowed via multiple inheritance by C3 linearization properties, despite not directly inheriting from each other. diff --git a/slither/utils/output.py b/slither/utils/output.py index 93ff5cdf5..f1ded8a38 100644 --- a/slither/utils/output.py +++ b/slither/utils/output.py @@ -78,7 +78,9 @@ def output_to_zip(filename: str, error: Optional[str], results: Dict, zip_type: logger.info(yellow(f"{filename} exists already, the overwrite is prevented")) else: with ZipFile( - filename, "w", compression=ZIP_TYPES_ACCEPTED.get(zip_type, zipfile.ZIP_LZMA), + filename, + "w", + compression=ZIP_TYPES_ACCEPTED.get(zip_type, zipfile.ZIP_LZMA), ) as file_desc: file_desc.writestr("slither_results.json", json.dumps(json_result).encode("utf8")) @@ -355,7 +357,11 @@ class Output: additional_fields = {} type_specific_fields = {"parent": _create_parent_element(enum)} element = _create_base_element( - "enum", enum.name, enum.source_mapping, type_specific_fields, additional_fields, + "enum", + enum.name, + enum.source_mapping, + type_specific_fields, + additional_fields, ) self._data["elements"].append(element) @@ -371,7 +377,11 @@ class Output: additional_fields = {} type_specific_fields = {"parent": _create_parent_element(struct)} element = _create_base_element( - "struct", struct.name, struct.source_mapping, type_specific_fields, additional_fields, + "struct", + struct.name, + struct.source_mapping, + type_specific_fields, + additional_fields, ) self._data["elements"].append(element) @@ -390,7 +400,11 @@ class Output: "signature": event.full_name, } element = _create_base_element( - "event", event.name, event.source_mapping, type_specific_fields, additional_fields, + "event", + event.name, + event.source_mapping, + type_specific_fields, + additional_fields, ) self._data["elements"].append(element) @@ -410,7 +424,11 @@ class Output: } node_name = str(node.expression) if node.expression else "" element = _create_base_element( - "node", node_name, node.source_mapping, type_specific_fields, additional_fields, + "node", + node_name, + node.source_mapping, + type_specific_fields, + additional_fields, ) self._data["elements"].append(element) @@ -461,7 +479,10 @@ class Output: ################################################################################### def add_pretty_table( - self, content: MyPrettyTable, name: str, additional_fields: Optional[Dict] = None, + self, + content: MyPrettyTable, + name: str, + additional_fields: Optional[Dict] = None, ): if additional_fields is None: additional_fields = {} @@ -478,7 +499,11 @@ class Output: ################################################################################### def add_other( - self, name: str, source_mapping, slither, additional_fields: Optional[Dict] = None, + self, + name: str, + source_mapping, + slither, + additional_fields: Optional[Dict] = None, ): # If this a tuple with (filename, start, end), convert it to a source mapping. if additional_fields is None: @@ -489,7 +514,10 @@ class Output: source_id = next( ( source_unit_id - for (source_unit_id, source_unit_filename,) in slither.source_units.items() + for ( + source_unit_id, + source_unit_filename, + ) in slither.source_units.items() if source_unit_filename == filename ), -1, diff --git a/slither/visitors/slithir/expression_to_slithir.py b/slither/visitors/slithir/expression_to_slithir.py index 1fc024fb8..d3ccf4858 100644 --- a/slither/visitors/slithir/expression_to_slithir.py +++ b/slither/visitors/slithir/expression_to_slithir.py @@ -370,9 +370,17 @@ class ExpressionToSlithIR(ExpressionVisitor): assert isinstance(type_expression_found, ElementaryTypeNameExpression) type_found = type_expression_found.type if expression.member_name == "min:": - op = Assignment(val, Constant(str(type_found.min), type_found), type_found,) + op = Assignment( + val, + Constant(str(type_found.min), type_found), + type_found, + ) else: - op = Assignment(val, Constant(str(type_found.max), type_found), type_found,) + op = Assignment( + val, + Constant(str(type_found.max), type_found), + type_found, + ) self._result.append(op) set_val(expression, val) return diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index c37700324..83a85caf4 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -468,7 +468,15 @@ def get_tests(solc_versions) -> Dict[str, List[str]]: return tests -Item = namedtuple("TestItem", ["test_id", "base_ver", "solc_ver", "is_legacy",],) +Item = namedtuple( + "TestItem", + [ + "test_id", + "base_ver", + "solc_ver", + "is_legacy", + ], +) def get_all_test() -> List[Item]: From fedf24ce4f0f6fbc238b5b0acc50cf36c4e92a51 Mon Sep 17 00:00:00 2001 From: Josselin Date: Sun, 7 Mar 2021 17:55:13 +0100 Subject: [PATCH 35/35] Fix pylint Split CI into three separate process --- .github/workflows/black.yml | 48 ++++++++++++++++++++ .github/workflows/linter.yml | 25 ----------- .github/workflows/pylint.yml | 49 +++++++++++++++++++++ slither/tools/flattening/export/__init__.py | 1 - 4 files changed, 97 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/black.yml create mode 100644 .github/workflows/pylint.yml diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml new file mode 100644 index 000000000..6242bd1cb --- /dev/null +++ b/.github/workflows/black.yml @@ -0,0 +1,48 @@ +--- +name: Lint Code Base + +defaults: + run: + # To load bashrc + shell: bash -ieo pipefail {0} + +on: + pull_request: + branches: [master, dev] + schedule: + # run CI every day even if no PRs/merges occur + - cron: '0 12 * * *' + +jobs: + build: + name: Lint Code Base + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v2 + + - name: Set up Python 3.6 + uses: actions/setup-python@v2 + with: + python-version: 3.6 + + - name: Install dependencies + run: | + pip install . + pip install deepdiff numpy + + mkdir -p .github/linters + cp pyproject.toml .github/linters + + - name: Black + uses: docker://github/super-linter:v3 + if: always() + env: + # run linter on everything to catch preexisting problems + VALIDATE_ALL_CODEBASE: true + DEFAULT_BRANCH: master + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Run only black + VALIDATE_PYTHON_BLACK: true + PYTHON_BLACK_CONFIG_FILE: pyproject.toml diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 2629567bb..452637a31 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -35,31 +35,6 @@ jobs: mkdir -p .github/linters cp pyproject.toml .github/linters - - name: Pylint - uses: docker://github/super-linter:v3 - if: always() - env: - # run linter on everything to catch preexisting problems - VALIDATE_ALL_CODEBASE: true - DEFAULT_BRANCH: master - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # Run only pylint - VALIDATE_PYTHON: true - VALIDATE_PYTHON_PYLINT: true - PYTHON_PYLINT_CONFIG_FILE: pyproject.toml - - - name: Black - uses: docker://github/super-linter:v3 - if: always() - env: - # run linter on everything to catch preexisting problems - VALIDATE_ALL_CODEBASE: true - DEFAULT_BRANCH: master - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # Run only black - VALIDATE_PYTHON_BLACK: true - PYTHON_BLACK_CONFIG_FILE: pyproject.toml - - name: Lint everything else uses: docker://github/super-linter:v3 if: always() diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml new file mode 100644 index 000000000..80b213aff --- /dev/null +++ b/.github/workflows/pylint.yml @@ -0,0 +1,49 @@ +--- +name: Lint Code Base + +defaults: + run: + # To load bashrc + shell: bash -ieo pipefail {0} + +on: + pull_request: + branches: [master, dev] + schedule: + # run CI every day even if no PRs/merges occur + - cron: '0 12 * * *' + +jobs: + build: + name: Lint Code Base + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v2 + + - name: Set up Python 3.6 + uses: actions/setup-python@v2 + with: + python-version: 3.6 + + - name: Install dependencies + run: | + pip install . + pip install deepdiff numpy + + mkdir -p .github/linters + cp pyproject.toml .github/linters + + - name: Pylint + uses: docker://github/super-linter:v3 + if: always() + env: + # run linter on everything to catch preexisting problems + VALIDATE_ALL_CODEBASE: true + DEFAULT_BRANCH: master + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Run only pylint + VALIDATE_PYTHON: true + VALIDATE_PYTHON_PYLINT: true + PYTHON_PYLINT_CONFIG_FILE: pyproject.toml diff --git a/slither/tools/flattening/export/__init__.py b/slither/tools/flattening/export/__init__.py index d3f5a12fa..e69de29bb 100644 --- a/slither/tools/flattening/export/__init__.py +++ b/slither/tools/flattening/export/__init__.py @@ -1 +0,0 @@ -