From 1c666c729deb6ae5262bf512b31c77a61bd8fca3 Mon Sep 17 00:00:00 2001 From: Josselin Date: Tue, 11 Dec 2018 05:02:02 -0500 Subject: [PATCH 1/6] Partial support of Solidity 0.5 (WIP) --- .travis.yml | 3 +- ...n.sh => tests_generate_expected_json_4.sh} | 2 +- scripts/tests_generate_expected_json_5.sh | 38 +++++++ scripts/travis_install.sh | 6 +- scripts/{travis_test.sh => travis_test_4.sh} | 4 +- scripts/travis_test_5.sh | 106 ++++++++++++++++++ slither/solc_parsing/declarations/function.py | 4 + .../expressions/expression_parsing.py | 1 + tests/backdoor.sol | 1 - tests/expected_json/backdoor.backdoor.json | 19 +--- tests/expected_json/backdoor.suicidal.json | 19 +--- tests/reentrancy-0.5.1.sol | 54 +++++++++ tests/uninitialized-0.5.1.sol | 58 ++++++++++ 13 files changed, 272 insertions(+), 43 deletions(-) rename scripts/{tests_generate_expected_json.sh => tests_generate_expected_json_4.sh} (96%) create mode 100755 scripts/tests_generate_expected_json_5.sh rename scripts/{travis_test.sh => travis_test_4.sh} (97%) create mode 100755 scripts/travis_test_5.sh create mode 100644 tests/reentrancy-0.5.1.sol create mode 100644 tests/uninitialized-0.5.1.sol diff --git a/.travis.yml b/.travis.yml index 5f5c642cf..8373f6b78 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ install: - scripts/travis_install.sh script: - - scripts/travis_test.sh + - scripts/travis_test_4.sh + - scripts/travis_test_5.sh diff --git a/scripts/tests_generate_expected_json.sh b/scripts/tests_generate_expected_json_4.sh similarity index 96% rename from scripts/tests_generate_expected_json.sh rename to scripts/tests_generate_expected_json_4.sh index 25c188467..8a78c967f 100755 --- a/scripts/tests_generate_expected_json.sh +++ b/scripts/tests_generate_expected_json_4.sh @@ -10,7 +10,7 @@ generate_expected_json(){ output_filename="$(basename $1 .sol).$2.json" # run slither detector on input file and save output as json - slither "$1" --disable-solc-warnings --detect "$2" --json "$DIR/../tests/expected_json/$output_filename" + slither "$1" --disable-solc-warnings --detect "$2" --json "$DIR/../tests/expected_json/$output_filename" --solc solc-0.4.25 } diff --git a/scripts/tests_generate_expected_json_5.sh b/scripts/tests_generate_expected_json_5.sh new file mode 100755 index 000000000..d4ce48ee0 --- /dev/null +++ b/scripts/tests_generate_expected_json_5.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +DIR="$(cd "$(dirname "$0")" && pwd)" + +# generate_expected_json file.sol detectors +generate_expected_json(){ + # generate output filename + # e.g. file: uninitialized.sol detector: uninitialized-state + # ---> uninitialized.uninitialized-state.json + output_filename="$(basename $1 .sol).$2.json" + + # run slither detector on input file and save output as json + slither "$1" --disable-solc-warnings --detect "$2" --json "$DIR/../tests/expected_json/$output_filename" --solc solc-0.5.1 + +} + +generate_expected_json tests/uninitialized-0.5.1.sol "uninitialized-state" +generate_expected_json tests/backdoor.sol "backdoor" +generate_expected_json tests/backdoor.sol "suicidal" +#generate_expected_json tests/pragma.0.4.24.sol "pragma" +#generate_expected_json tests/old_solc.sol.json "solc-version" +generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy" +#generate_expected_json tests/uninitialized_storage_pointer.sol "uninitialized-storage" +#generate_expected_json tests/tx_origin.sol "tx-origin" +#generate_expected_json tests/unused_state.sol "unused-state" +generate_expected_json tests/locked_ether.sol "locked-ether" +#generate_expected_json tests/arbitrary_send.sol "arbitrary-send" +#generate_expected_json tests/inline_assembly_contract.sol "assembly" +#generate_expected_json tests/inline_assembly_library.sol "assembly" +#generate_expected_json tests/low_level_calls.sol "low-level-calls" +#generate_expected_json tests/const_state_variables.sol "constable-states" +#generate_expected_json tests/external_function.sol "external-function" +#generate_expected_json tests/naming_convention.sol "naming-convention" +#generate_expected_json tests/uninitialized_local_variable.sol "uninitialized-local" +#generate_expected_json tests/controlled_delegatecall.sol "controlled-delegatecall" +#generate_expected_json tests/constant.sol "constant-function" + +#generate_expected_json tests/unused_return.sol "unused-return" diff --git a/scripts/travis_install.sh b/scripts/travis_install.sh index 2525ac704..cf45f33d8 100755 --- a/scripts/travis_install.sh +++ b/scripts/travis_install.sh @@ -4,8 +4,10 @@ python setup.py install pip install deepdiff function install_solc { - sudo wget -O /usr/bin/solc https://github.com/ethereum/solidity/releases/download/v0.4.24/solc-static-linux - sudo chmod +x /usr/bin/solc + sudo wget -O /usr/bin/solc https://github.com/ethereum/solidity/releases/download/v0.4.25/solc-static-linux + sudo chmod +x /usr/bin/solc-4.25 + sudo wget -O /usr/bin/solc https://github.com/ethereum/solidity/releases/download/v0.5.1/solc-static-linux + sudo chmod +x /usr/bin/solc-5.1 } install_solc diff --git a/scripts/travis_test.sh b/scripts/travis_test_4.sh similarity index 97% rename from scripts/travis_test.sh rename to scripts/travis_test_4.sh index 5d555af6c..57e1c85ac 100755 --- a/scripts/travis_test.sh +++ b/scripts/travis_test_4.sh @@ -10,7 +10,7 @@ test_slither(){ expected="$DIR/../tests/expected_json/$(basename $1 .sol).$2.json" # run slither detector on input file and save output as json - slither "$1" --disable-solc-warnings --detect "$2" --json "$DIR/tmp-test.json" + slither "$1" --disable-solc-warnings --detect "$2" --json "$DIR/tmp-test.json" --solc solc-0.4.25 if [ $? -eq 255 ] then echo "Slither crashed" @@ -37,7 +37,7 @@ test_slither(){ fi # run slither detector on input file and save output as json - slither "$1" --disable-solc-warnings --detect "$2" --compact-ast --json "$DIR/tmp-test.json" + slither "$1" --disable-solc-warnings --detect "$2" --compact-ast --json "$DIR/tmp-test.json" --solc solc-0.4.25 if [ $? -eq 255 ] then echo "Slither crashed" diff --git a/scripts/travis_test_5.sh b/scripts/travis_test_5.sh new file mode 100755 index 000000000..160d8804b --- /dev/null +++ b/scripts/travis_test_5.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash + +### Test Detectors + +DIR="$(cd "$(dirname "$0")" && pwd)" + +# test_slither file.sol detectors +test_slither(){ + + expected="$DIR/../tests/expected_json/$(basename $1 .sol).$2.json" + + # run slither detector on input file and save output as json + slither "$1" --disable-solc-warnings --detect "$2" --json "$DIR/tmp-test.json" --solc solc-0.5.1 + if [ $? -eq 255 ] + then + echo "Slither crashed" + exit -1 + fi + + if [ ! -f "$DIR/tmp-test.json" ]; then + echo "" + echo "Missing generated file" + echo "" + exit 1 + fi + + result=$(python "$DIR/json_diff.py" "$expected" "$DIR/tmp-test.json") + + rm "$DIR/tmp-test.json" + if [ "$result" != "{}" ]; then + echo "" + echo "failed test of file: $1, detector: $2" + echo "" + echo "$result" + echo "" + exit 1 + fi + + # run slither detector on input file and save output as json + slither "$1" --disable-solc-warnings --detect "$2" --compact-ast --json "$DIR/tmp-test.json" --solc solc-0.5.1 + if [ $? -eq 255 ] + then + echo "Slither crashed" + exit -1 + fi + + if [ ! -f "$DIR/tmp-test.json" ]; then + echo "" + echo "Missing generated file" + echo "" + exit 1 + fi + + result=$(python "$DIR/json_diff.py" "$expected" "$DIR/tmp-test.json") + + rm "$DIR/tmp-test.json" + if [ "$result" != "{}" ]; then + echo "" + echo "failed test of file: $1, detector: $2" + echo "" + echo "$result" + echo "" + exit 1 + fi +} + + +test_slither tests/uninitialized-0.5.1.sol "uninitialized-state" +test_slither tests/backdoor.sol "backdoor" +test_slither tests/backdoor.sol "suicidal" +test_slither tests/old_solc.sol.json "solc-version" +test_slither tests/reentrancy-0.5.1.sol "reentrancy" +test_slither tests/uninitialized_storage_pointer.sol "uninitialized-storage" +test_slither tests/tx_origin.sol "tx-origin" +test_slither tests/unused_state.sol "unused-state" +test_slither tests/locked_ether.sol "locked-ether" +test_slither tests/arbitrary_send.sol "arbitrary-send" +test_slither tests/inline_assembly_contract.sol "assembly" +test_slither tests/inline_assembly_library.sol "assembly" +test_slither tests/low_level_calls.sol "low-level-calls" +test_slither tests/const_state_variables.sol "constable-states" +test_slither tests/external_function.sol "external-function" +test_slither tests/naming_convention.sol "naming-convention" +#test_slither tests/complex_func.sol "complex-function" +test_slither tests/controlled_delegatecall.sol "controlled-delegatecall" +test_slither tests/constant.sol "constant-function" +test_slither tests/unused_return.sol "unused-return" + + +### Test scripts + +python examples/scripts/functions_called.py examples/scripts/functions_called.sol +if [ $? -ne 0 ]; then + exit 1 +fi + +python examples/scripts/functions_writing.py examples/scripts/functions_writing.sol +if [ $? -ne 0 ]; then + exit 1 +fi + +python examples/scripts/variable_in_condition.py examples/scripts/variable_in_condition.sol +if [ $? -ne 0 ]; then + exit 1 +fi +exit 0 diff --git a/slither/solc_parsing/declarations/function.py b/slither/solc_parsing/declarations/function.py index 7e8b1c6fe..a3e192baa 100644 --- a/slither/solc_parsing/declarations/function.py +++ b/slither/solc_parsing/declarations/function.py @@ -79,6 +79,10 @@ class FunctionSolc(Function): if 'isConstructor' in attributes: self._is_constructor = attributes['isConstructor'] + if 'kind' in attributes: + if attributes['kind'] == 'constructor': + self._is_constructor = True + if 'visibility' in attributes: self._visibility = attributes['visibility'] # old solc diff --git a/slither/solc_parsing/expressions/expression_parsing.py b/slither/solc_parsing/expressions/expression_parsing.py index a12fe4307..2dc6aefac 100644 --- a/slither/solc_parsing/expressions/expression_parsing.py +++ b/slither/solc_parsing/expressions/expression_parsing.py @@ -216,6 +216,7 @@ def filter_name(value): value = value.replace(' pure', '') value = value.replace(' view', '') value = value.replace(' constant', '') + value = value.replace(' payable', '') value = value.replace('function (', 'function(') value = value.replace('returns (', 'returns(') diff --git a/tests/backdoor.sol b/tests/backdoor.sol index 94cada911..428c794d4 100644 --- a/tests/backdoor.sol +++ b/tests/backdoor.sol @@ -1,4 +1,3 @@ -pragma solidity ^0.4.24; contract C{ diff --git a/tests/expected_json/backdoor.backdoor.json b/tests/expected_json/backdoor.backdoor.json index 3b289b2b9..58d71a5fb 100644 --- a/tests/expected_json/backdoor.backdoor.json +++ b/tests/expected_json/backdoor.backdoor.json @@ -1,18 +1 @@ -[ - { - "check": "backdoor", - "function": { - "name": "i_am_a_backdoor", - "source_mapping": { - "filename": "tests/backdoor.sol", - "length": 74, - "lines": [ - 5, - 6, - 7 - ], - "start": 43 - } - } - } -] \ No newline at end of file +[{"check": "backdoor", "function": {"name": "i_am_a_backdoor", "source_mapping": {"start": 18, "length": 74, "filename": "tests/backdoor.sol", "lines": [4, 5, 6]}}}] \ No newline at end of file diff --git a/tests/expected_json/backdoor.suicidal.json b/tests/expected_json/backdoor.suicidal.json index 6fdd07bd7..092ac5f0b 100644 --- a/tests/expected_json/backdoor.suicidal.json +++ b/tests/expected_json/backdoor.suicidal.json @@ -1,18 +1 @@ -[ - { - "check": "suicidal", - "function": { - "name": "i_am_a_backdoor", - "source_mapping": { - "filename": "tests/backdoor.sol", - "length": 74, - "lines": [ - 5, - 6, - 7 - ], - "start": 43 - } - } - } -] \ No newline at end of file +[{"check": "suicidal", "function": {"name": "i_am_a_backdoor", "source_mapping": {"start": 18, "length": 74, "filename": "tests/backdoor.sol", "lines": [4, 5, 6]}}}] \ No newline at end of file diff --git a/tests/reentrancy-0.5.1.sol b/tests/reentrancy-0.5.1.sol new file mode 100644 index 000000000..a2151ed90 --- /dev/null +++ b/tests/reentrancy-0.5.1.sol @@ -0,0 +1,54 @@ +pragma solidity ^0.5.0; + +contract Reentrancy { + mapping (address => uint) userBalance; + + function getBalance(address u) view public returns(uint){ + return userBalance[u]; + } + + function addToBalance() payable public{ + userBalance[msg.sender] += msg.value; + } + + function withdrawBalance() public{ + // send userBalance[msg.sender] ethers to msg.sender + // if mgs.sender is a contract, it will call its fallback function + (bool ret, bytes memory mem) = msg.sender.call.value(userBalance[msg.sender])(""); + if( ! ret ){ + revert(); + } + userBalance[msg.sender] = 0; + } + + function withdrawBalance_fixed() public{ + // To protect against re-entrancy, the state variable + // has to be change before the call + uint amount = userBalance[msg.sender]; + userBalance[msg.sender] = 0; + (bool ret, bytes memory mem) = msg.sender.call.value(amount)(""); + if( ! ret ){ + revert(); + } + } + + function withdrawBalance_fixed_2() public{ + // send() and transfer() are safe against reentrancy + // they do not transfer the remaining gas + // and they give just enough gas to execute few instructions + // in the fallback function (no further call possible) + msg.sender.transfer(userBalance[msg.sender]); + userBalance[msg.sender] = 0; + } + + function withdrawBalance_fixed_3() public{ + // The state can be changed + // But it is fine, as it can only occur if the transaction fails + uint amount = userBalance[msg.sender]; + userBalance[msg.sender] = 0; + (bool ret, bytes memory mem) = msg.sender.call.value(amount)(""); + if( ! ret ){ + userBalance[msg.sender] = amount; + } + } +} diff --git a/tests/uninitialized-0.5.1.sol b/tests/uninitialized-0.5.1.sol new file mode 100644 index 000000000..b12e44e77 --- /dev/null +++ b/tests/uninitialized-0.5.1.sol @@ -0,0 +1,58 @@ +pragma solidity ^0.5.0; + +contract Uninitialized{ + + address payable destination; + + function transfer() payable public{ + destination.transfer(msg.value); + } + +} + + +contract Test { + mapping (address => uint) balances; + mapping (address => uint) balancesInitialized; + + + function init() public{ + balancesInitialized[msg.sender] = 0; + } + + function use() view public{ + // random operation to use the mapping + require(balances[msg.sender] == balancesInitialized[msg.sender]); + } +} + +library Lib{ + + struct MyStruct{ + uint val; + } + + function set(MyStruct storage st, uint v) public{ + st.val = v; + } + +} + + +contract Test2 { + using Lib for Lib.MyStruct; + + Lib.MyStruct st; + Lib.MyStruct stInitiliazed; + uint v; // v is used as parameter of the lib, but is never init + + function init() public{ + stInitiliazed.set(v); + } + + function use() view public{ + // random operation to use the structure + require(st.val == stInitiliazed.val); + } + +} From 0c63564669516831ac0d12cbb63ae8ff08a5669b Mon Sep 17 00:00:00 2001 From: Josselin Date: Tue, 11 Dec 2018 11:28:00 -0500 Subject: [PATCH 2/6] Add Solidity 0.5 Support (WIP) Update travis tests to test both Solidity 0.4 and Solidity 0.5 --- scripts/tests_generate_expected_json_5.sh | 25 +++------- scripts/travis_test_5.sh | 13 +++-- .../core/declarations/solidity_variables.py | 1 + .../expressions/expression_parsing.py | 2 +- tests/arbitrary_send-0.5.1.sol | 41 ++++++++++++++++ tests/arbitrary_send.sol | 16 +++--- tests/const_state_variables.sol | 4 +- tests/constant-0.5.1.sol | 18 +++++++ tests/controlled_delegatecall.sol | 14 +++--- .../arbitrary_send-0.5.1.arbitrary-send.json | 1 + .../arbitrary_send.arbitrary-send.json | 2 +- ...onst_state_variables.constable-states.json | 2 +- .../constant-0.5.1.constant-function.json | 1 + ..._delegatecall.controlled-delegatecall.json | 2 +- .../external_function.external-function.json | 2 +- ...line_assembly_contract-0.5.1.assembly.json | 1 + ...nline_assembly_library-0.5.1.assembly.json | 1 + .../locked_ether-0.5.1.locked-ether.json | 1 + .../locked_ether.locked-ether.json | 2 +- .../low_level_calls.low-level-calls.json | 2 +- .../naming_convention.naming-convention.json | 2 +- .../reentrancy-0.5.1.reentrancy.json | 1 + .../tx_origin-0.5.1.tx-origin.json | 1 + tests/expected_json/tx_origin.tx-origin.json | 2 +- ...initialized-0.5.1.uninitialized-state.json | 1 + .../unused_return.unused-return.json | 2 +- .../unused_state.unused-state.json | 2 +- tests/external_function.sol | 6 +-- tests/external_function_test_2.sol | 2 +- tests/inline_assembly_contract-0.5.1.sol | 22 +++++++++ tests/inline_assembly_library-0.5.1.sol | 49 +++++++++++++++++++ tests/locked_ether-0.5.1.sol | 26 ++++++++++ tests/low_level_calls.sol | 10 ++-- tests/naming_convention.sol | 14 +++--- tests/tx_origin-0.5.1.sol | 26 ++++++++++ tests/tx_origin.sol | 2 +- tests/unused_return.sol | 6 +-- tests/unused_state.sol | 6 +-- 38 files changed, 256 insertions(+), 75 deletions(-) create mode 100644 tests/arbitrary_send-0.5.1.sol create mode 100644 tests/constant-0.5.1.sol create mode 100644 tests/expected_json/arbitrary_send-0.5.1.arbitrary-send.json create mode 100644 tests/expected_json/constant-0.5.1.constant-function.json create mode 100644 tests/expected_json/inline_assembly_contract-0.5.1.assembly.json create mode 100644 tests/expected_json/inline_assembly_library-0.5.1.assembly.json create mode 100644 tests/expected_json/locked_ether-0.5.1.locked-ether.json create mode 100644 tests/expected_json/reentrancy-0.5.1.reentrancy.json create mode 100644 tests/expected_json/tx_origin-0.5.1.tx-origin.json create mode 100644 tests/expected_json/uninitialized-0.5.1.uninitialized-state.json create mode 100644 tests/inline_assembly_contract-0.5.1.sol create mode 100644 tests/inline_assembly_library-0.5.1.sol create mode 100644 tests/locked_ether-0.5.1.sol create mode 100644 tests/tx_origin-0.5.1.sol diff --git a/scripts/tests_generate_expected_json_5.sh b/scripts/tests_generate_expected_json_5.sh index d4ce48ee0..a6b0feea2 100755 --- a/scripts/tests_generate_expected_json_5.sh +++ b/scripts/tests_generate_expected_json_5.sh @@ -15,24 +15,15 @@ generate_expected_json(){ } generate_expected_json tests/uninitialized-0.5.1.sol "uninitialized-state" -generate_expected_json tests/backdoor.sol "backdoor" -generate_expected_json tests/backdoor.sol "suicidal" +#generate_expected_json tests/backdoor.sol "backdoor" +#generate_expected_json tests/backdoor.sol "suicidal" #generate_expected_json tests/pragma.0.4.24.sol "pragma" #generate_expected_json tests/old_solc.sol.json "solc-version" generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy" #generate_expected_json tests/uninitialized_storage_pointer.sol "uninitialized-storage" -#generate_expected_json tests/tx_origin.sol "tx-origin" -#generate_expected_json tests/unused_state.sol "unused-state" -generate_expected_json tests/locked_ether.sol "locked-ether" -#generate_expected_json tests/arbitrary_send.sol "arbitrary-send" -#generate_expected_json tests/inline_assembly_contract.sol "assembly" -#generate_expected_json tests/inline_assembly_library.sol "assembly" -#generate_expected_json tests/low_level_calls.sol "low-level-calls" -#generate_expected_json tests/const_state_variables.sol "constable-states" -#generate_expected_json tests/external_function.sol "external-function" -#generate_expected_json tests/naming_convention.sol "naming-convention" -#generate_expected_json tests/uninitialized_local_variable.sol "uninitialized-local" -#generate_expected_json tests/controlled_delegatecall.sol "controlled-delegatecall" -#generate_expected_json tests/constant.sol "constant-function" - -#generate_expected_json tests/unused_return.sol "unused-return" +generate_expected_json tests/tx_origin-0.5.1.sol "tx-origin" +generate_expected_json tests/locked_ether-0.5.1.sol "locked-ether" +generate_expected_json tests/arbitrary_send-0.5.1.sol "arbitrary-send" +generate_expected_json tests/inline_assembly_contract-0.5.1.sol "assembly" +generate_expected_json tests/inline_assembly_library-0.5.1.sol "assembly" +generate_expected_json tests/constant-0.5.1.sol "constant-function" diff --git a/scripts/travis_test_5.sh b/scripts/travis_test_5.sh index 160d8804b..0f7fb82d9 100755 --- a/scripts/travis_test_5.sh +++ b/scripts/travis_test_5.sh @@ -70,20 +70,19 @@ test_slither tests/backdoor.sol "backdoor" test_slither tests/backdoor.sol "suicidal" test_slither tests/old_solc.sol.json "solc-version" test_slither tests/reentrancy-0.5.1.sol "reentrancy" -test_slither tests/uninitialized_storage_pointer.sol "uninitialized-storage" -test_slither tests/tx_origin.sol "tx-origin" +test_slither tests/tx_origin-0.5.1.sol "tx-origin" test_slither tests/unused_state.sol "unused-state" -test_slither tests/locked_ether.sol "locked-ether" -test_slither tests/arbitrary_send.sol "arbitrary-send" -test_slither tests/inline_assembly_contract.sol "assembly" -test_slither tests/inline_assembly_library.sol "assembly" +test_slither tests/locked_ether-0.5.1.sol "locked-ether" +test_slither tests/arbitrary_send-0.5.1.sol "arbitrary-send" +test_slither tests/inline_assembly_contract-0.5.1.sol "assembly" +test_slither tests/inline_assembly_library-0.5.1.sol "assembly" test_slither tests/low_level_calls.sol "low-level-calls" test_slither tests/const_state_variables.sol "constable-states" test_slither tests/external_function.sol "external-function" test_slither tests/naming_convention.sol "naming-convention" #test_slither tests/complex_func.sol "complex-function" test_slither tests/controlled_delegatecall.sol "controlled-delegatecall" -test_slither tests/constant.sol "constant-function" +test_slither tests/constant-0.5.1.sol "constant-function" test_slither tests/unused_return.sol "unused-return" diff --git a/slither/core/declarations/solidity_variables.py b/slither/core/declarations/solidity_variables.py index 36f0795f1..1983667f8 100644 --- a/slither/core/declarations/solidity_variables.py +++ b/slither/core/declarations/solidity_variables.py @@ -34,6 +34,7 @@ SOLIDITY_FUNCTIONS = {"gasleft()":['uint256'], "addmod(uint256,uint256,uint256)":['uint256'], "mulmod(uint256,uint256,uint256)":['uint256'], "keccak256()":['bytes32'], + "keccak256(bytes)":['bytes32'], # Solidity 0.5 "sha256()":['bytes32'], "sha3()":['bytes32'], "ripemd160()":['bytes32'], diff --git a/slither/solc_parsing/expressions/expression_parsing.py b/slither/solc_parsing/expressions/expression_parsing.py index 2dc6aefac..53e3111d0 100644 --- a/slither/solc_parsing/expressions/expression_parsing.py +++ b/slither/solc_parsing/expressions/expression_parsing.py @@ -380,7 +380,7 @@ def parse_expression(expression, caller_context): if is_compact_ast: value = expression['value'] - if not value: + if not value and value != "": value = '0x'+expression['hexValue'] else: value = expression['attributes']['value'] diff --git a/tests/arbitrary_send-0.5.1.sol b/tests/arbitrary_send-0.5.1.sol new file mode 100644 index 000000000..9a0c743c4 --- /dev/null +++ b/tests/arbitrary_send-0.5.1.sol @@ -0,0 +1,41 @@ +contract Test{ + + address payable destination; + + mapping (address => uint) balances; + + constructor() public{ + balances[msg.sender] = 0; + } + + function direct() public{ + msg.sender.send(address(this).balance); + } + + function init() public{ + destination = msg.sender; + } + + function indirect() public{ + destination.send(address(this).balance); + } + + // these are legitimate calls + // and should not be detected + function repay() payable public{ + msg.sender.transfer(msg.value); + } + + function withdraw() public{ + uint val = balances[msg.sender]; + msg.sender.send(val); + } + + function buy() payable public{ + uint value_send = msg.value; + uint value_spent = 0 ; // simulate a buy of tokens + uint remaining = value_send - value_spent; + msg.sender.send(remaining); +} + +} diff --git a/tests/arbitrary_send.sol b/tests/arbitrary_send.sol index 3544a903c..b46576b18 100644 --- a/tests/arbitrary_send.sol +++ b/tests/arbitrary_send.sol @@ -8,30 +8,30 @@ contract Test{ balances[msg.sender] = 0; } - function direct(){ - msg.sender.send(this.balance); + function direct() public{ + msg.sender.send(address(this).balance); } - function init(){ + function init() public{ destination = msg.sender; } - function indirect(){ - destination.send(this.balance); + function indirect() public{ + destination.send(address(this).balance); } // these are legitimate calls // and should not be detected - function repay() payable{ + function repay() payable public{ msg.sender.transfer(msg.value); } - function withdraw(){ + function withdraw() public{ uint val = balances[msg.sender]; msg.sender.send(val); } - function buy() payable{ + function buy() payable public{ uint value_send = msg.value; uint value_spent = 0 ; // simulate a buy of tokens uint remaining = value_send - value_spent; diff --git a/tests/const_state_variables.sol b/tests/const_state_variables.sol index f518ceb84..94c940dd6 100644 --- a/tests/const_state_variables.sol +++ b/tests/const_state_variables.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +//pragma solidity ^0.4.24; contract A { @@ -25,7 +25,7 @@ contract B is A { address public mySistersAddress = 0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E; - function () public { + function () external { used = 0; } diff --git a/tests/constant-0.5.1.sol b/tests/constant-0.5.1.sol new file mode 100644 index 000000000..3293ab45d --- /dev/null +++ b/tests/constant-0.5.1.sol @@ -0,0 +1,18 @@ +contract Constant { + + uint a; + + + function test_view_shadow() public view{ + uint a; + a = 0; + } + + function test_view() public view{ + a; + } + + function test_assembly_bug() public view{ + assembly{} + } +} diff --git a/tests/controlled_delegatecall.sol b/tests/controlled_delegatecall.sol index dbf38315c..d3d3a78dd 100644 --- a/tests/controlled_delegatecall.sol +++ b/tests/controlled_delegatecall.sol @@ -1,25 +1,25 @@ contract C{ - address addr_good = 0x41; + address addr_good = address(0x41); address addr_bad ; bytes4 func_id; - function bad_delegate_call(bytes data){ + function bad_delegate_call(bytes memory data) public{ addr_good.delegatecall(data); addr_bad.delegatecall(data); } - function set(bytes4 id){ + function set(bytes4 id) public{ func_id = id; addr_bad = msg.sender; } - function bad_delegate_call2(bytes data){ - addr_bad.delegatecall(func_id, data); + function bad_delegate_call2(bytes memory data) public{ + addr_bad.delegatecall(abi.encode(func_id, data)); } - function good_delegate_call(bytes data){ - addr_good.delegatecall(bytes4(0x41), data); + function good_delegate_call(bytes memory data) public{ + addr_good.delegatecall(abi.encode(bytes4(""), data)); } } diff --git a/tests/expected_json/arbitrary_send-0.5.1.arbitrary-send.json b/tests/expected_json/arbitrary_send-0.5.1.arbitrary-send.json new file mode 100644 index 000000000..7a9cba1df --- /dev/null +++ b/tests/expected_json/arbitrary_send-0.5.1.arbitrary-send.json @@ -0,0 +1 @@ +[{"check": "arbitrary-send", "impact": "High", "confidence": "Medium", "description": "Test.direct (tests/arbitrary_send-0.5.1.sol#11-13) sends eth to arbirary user\n\tDangerous calls:\n\t- msg.sender.send(address(this).balance) (tests/arbitrary_send-0.5.1.sol#12)\n", "function": {"name": "direct", "source_mapping": {"start": 162, "length": 79, "filename": "tests/arbitrary_send-0.5.1.sol", "lines": [11, 12, 13]}, "contract": {"name": "Test", "source_mapping": {"start": 0, "length": 884, "filename": "tests/arbitrary_send-0.5.1.sol", "lines": [1, 2, 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]}}}, "expressions": [{"expression": "msg.sender.send(address(this).balance)", "source_mapping": {"start": 196, "length": 38, "filename": "tests/arbitrary_send-0.5.1.sol", "lines": [12]}}]}, {"check": "arbitrary-send", "impact": "High", "confidence": "Medium", "description": "Test.indirect (tests/arbitrary_send-0.5.1.sol#19-21) sends eth to arbirary user\n\tDangerous calls:\n\t- destination.send(address(this).balance) (tests/arbitrary_send-0.5.1.sol#20)\n", "function": {"name": "indirect", "source_mapping": {"start": 316, "length": 82, "filename": "tests/arbitrary_send-0.5.1.sol", "lines": [19, 20, 21]}, "contract": {"name": "Test", "source_mapping": {"start": 0, "length": 884, "filename": "tests/arbitrary_send-0.5.1.sol", "lines": [1, 2, 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]}}}, "expressions": [{"expression": "destination.send(address(this).balance)", "source_mapping": {"start": 352, "length": 39, "filename": "tests/arbitrary_send-0.5.1.sol", "lines": [20]}}]}] \ No newline at end of file diff --git a/tests/expected_json/arbitrary_send.arbitrary-send.json b/tests/expected_json/arbitrary_send.arbitrary-send.json index 8a134883b..1cf98c643 100644 --- a/tests/expected_json/arbitrary_send.arbitrary-send.json +++ b/tests/expected_json/arbitrary_send.arbitrary-send.json @@ -1 +1 @@ -[{"check": "arbitrary-send", "impact": "High", "confidence": "Medium", "description": "Test.direct (tests/arbitrary_send.sol#11-13) sends eth to arbirary user\n\tDangerous calls:\n\t- msg.sender.send(this.balance) (tests/arbitrary_send.sol#12)\n", "function": {"name": "direct", "source_mapping": {"start": 147, "length": 63, "filename": "tests/arbitrary_send.sol", "lines": [11, 12, 13]}, "contract": {"name": "Test", "source_mapping": {"start": 0, "length": 809, "filename": "tests/arbitrary_send.sol", "lines": [1, 2, 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]}}}, "expressions": [{"expression": "msg.sender.send(this.balance)", "source_mapping": {"start": 174, "length": 29, "filename": "tests/arbitrary_send.sol", "lines": [12]}}]}, {"check": "arbitrary-send", "impact": "High", "confidence": "Medium", "description": "Test.indirect (tests/arbitrary_send.sol#19-21) sends eth to arbirary user\n\tDangerous calls:\n\t- destination.send(this.balance) (tests/arbitrary_send.sol#20)\n", "function": {"name": "indirect", "source_mapping": {"start": 278, "length": 66, "filename": "tests/arbitrary_send.sol", "lines": [19, 20, 21]}, "contract": {"name": "Test", "source_mapping": {"start": 0, "length": 809, "filename": "tests/arbitrary_send.sol", "lines": [1, 2, 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]}}}, "expressions": [{"expression": "destination.send(this.balance)", "source_mapping": {"start": 307, "length": 30, "filename": "tests/arbitrary_send.sol", "lines": [20]}}]}] \ No newline at end of file +[{"check": "arbitrary-send", "impact": "High", "confidence": "Medium", "description": "Test.direct (tests/arbitrary_send.sol#11-13) sends eth to arbirary user\n\tDangerous calls:\n\t- msg.sender.send(address(this).balance) (tests/arbitrary_send.sol#12)\n", "function": {"name": "direct", "source_mapping": {"start": 147, "length": 79, "filename": "tests/arbitrary_send.sol", "lines": [11, 12, 13]}, "contract": {"name": "Test", "source_mapping": {"start": 0, "length": 869, "filename": "tests/arbitrary_send.sol", "lines": [1, 2, 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]}}}, "expressions": [{"expression": "msg.sender.send(address(this).balance)", "source_mapping": {"start": 181, "length": 38, "filename": "tests/arbitrary_send.sol", "lines": [12]}}]}, {"check": "arbitrary-send", "impact": "High", "confidence": "Medium", "description": "Test.indirect (tests/arbitrary_send.sol#19-21) sends eth to arbirary user\n\tDangerous calls:\n\t- destination.send(address(this).balance) (tests/arbitrary_send.sol#20)\n", "function": {"name": "indirect", "source_mapping": {"start": 301, "length": 82, "filename": "tests/arbitrary_send.sol", "lines": [19, 20, 21]}, "contract": {"name": "Test", "source_mapping": {"start": 0, "length": 869, "filename": "tests/arbitrary_send.sol", "lines": [1, 2, 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]}}}, "expressions": [{"expression": "destination.send(address(this).balance)", "source_mapping": {"start": 337, "length": 39, "filename": "tests/arbitrary_send.sol", "lines": [20]}}]}] \ No newline at end of file diff --git a/tests/expected_json/const_state_variables.constable-states.json b/tests/expected_json/const_state_variables.constable-states.json index a83b1ae5f..4f7c002c3 100644 --- a/tests/expected_json/const_state_variables.constable-states.json +++ b/tests/expected_json/const_state_variables.constable-states.json @@ -1 +1 @@ -[{"check": "constable-states", "impact": "Informational", "confidence": "High", "description": "A.myFriendsAddress should be constant (tests/const_state_variables.sol#7)\nA.test should be constant (tests/const_state_variables.sol#10)\nA.text2 should be constant (tests/const_state_variables.sol#14)\n", "variables": [{"name": "myFriendsAddress", "source_mapping": {"start": 130, "length": 76, "filename": "tests/const_state_variables.sol", "lines": [7]}}, {"name": "test", "source_mapping": {"start": 235, "length": 20, "filename": "tests/const_state_variables.sol", "lines": [10]}}, {"name": "text2", "source_mapping": {"start": 331, "length": 20, "filename": "tests/const_state_variables.sol", "lines": [14]}}]}, {"check": "constable-states", "impact": "Informational", "confidence": "High", "description": "B.mySistersAddress should be constant (tests/const_state_variables.sol#26)\n", "variables": [{"name": "mySistersAddress", "source_mapping": {"start": 494, "length": 76, "filename": "tests/const_state_variables.sol", "lines": [26]}}]}] \ No newline at end of file +[{"check": "constable-states", "impact": "Informational", "confidence": "High", "description": "A.myFriendsAddress should be constant (tests/const_state_variables.sol#7)\nA.test should be constant (tests/const_state_variables.sol#10)\nA.text2 should be constant (tests/const_state_variables.sol#14)\n", "variables": [{"name": "myFriendsAddress", "source_mapping": {"start": 132, "length": 76, "filename": "tests/const_state_variables.sol", "lines": [7]}}, {"name": "test", "source_mapping": {"start": 237, "length": 20, "filename": "tests/const_state_variables.sol", "lines": [10]}}, {"name": "text2", "source_mapping": {"start": 333, "length": 20, "filename": "tests/const_state_variables.sol", "lines": [14]}}]}, {"check": "constable-states", "impact": "Informational", "confidence": "High", "description": "B.mySistersAddress should be constant (tests/const_state_variables.sol#26)\n", "variables": [{"name": "mySistersAddress", "source_mapping": {"start": 496, "length": 76, "filename": "tests/const_state_variables.sol", "lines": [26]}}]}] \ No newline at end of file diff --git a/tests/expected_json/constant-0.5.1.constant-function.json b/tests/expected_json/constant-0.5.1.constant-function.json new file mode 100644 index 000000000..711e2e952 --- /dev/null +++ b/tests/expected_json/constant-0.5.1.constant-function.json @@ -0,0 +1 @@ +[{"check": "constant-function", "impact": "Medium", "confidence": "Medium", "description": "Constant.test_assembly_bug (tests/constant-0.5.1.sol#15-17) is declared view but contains assembly code\n", "function": {"name": "test_assembly_bug", "source_mapping": {"start": 185, "length": 66, "filename": "tests/constant-0.5.1.sol", "lines": [15, 16, 17]}, "contract": {"name": "Constant", "source_mapping": {"start": 0, "length": 253, "filename": "tests/constant-0.5.1.sol", "lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]}}}, "variables": [], "contains_assembly": true}] \ No newline at end of file diff --git a/tests/expected_json/controlled_delegatecall.controlled-delegatecall.json b/tests/expected_json/controlled_delegatecall.controlled-delegatecall.json index 4a059d7ed..182e67eb0 100644 --- a/tests/expected_json/controlled_delegatecall.controlled-delegatecall.json +++ b/tests/expected_json/controlled_delegatecall.controlled-delegatecall.json @@ -1 +1 @@ -[{"check": "controlled-delegatecall", "impact": "High", "confidence": "Medium", "description": "C.bad_delegate_call (tests/controlled_delegatecall.sol#8-11) uses delegatecall to a input-controlled function id\n\taddr_bad.delegatecall(data) (tests/controlled_delegatecall.sol#10)\n", "function": {"name": "bad_delegate_call", "source_mapping": {"start": 92, "length": 120, "filename": "tests/controlled_delegatecall.sol", "lines": [8, 9, 10, 11]}, "contract": {"name": "C", "source_mapping": {"start": 0, "length": 505, "filename": "tests/controlled_delegatecall.sol", "lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]}}}, "expressions": [{"expression": "addr_bad.delegatecall(data)", "source_mapping": {"start": 178, "length": 27, "filename": "tests/controlled_delegatecall.sol", "lines": [10]}}]}, {"check": "controlled-delegatecall", "impact": "High", "confidence": "Medium", "description": "C.bad_delegate_call2 (tests/controlled_delegatecall.sol#18-20) uses delegatecall to a input-controlled function id\n\taddr_bad.delegatecall(func_id,data) (tests/controlled_delegatecall.sol#19)\n", "function": {"name": "bad_delegate_call2", "source_mapping": {"start": 307, "length": 92, "filename": "tests/controlled_delegatecall.sol", "lines": [18, 19, 20]}, "contract": {"name": "C", "source_mapping": {"start": 0, "length": 505, "filename": "tests/controlled_delegatecall.sol", "lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]}}}, "expressions": [{"expression": "addr_bad.delegatecall(func_id,data)", "source_mapping": {"start": 356, "length": 36, "filename": "tests/controlled_delegatecall.sol", "lines": [19]}}]}] \ No newline at end of file +[{"check": "controlled-delegatecall", "impact": "High", "confidence": "Medium", "description": "C.bad_delegate_call (tests/controlled_delegatecall.sol#8-11) uses delegatecall to a input-controlled function id\n\taddr_bad.delegatecall(data) (tests/controlled_delegatecall.sol#10)\n", "function": {"name": "bad_delegate_call", "source_mapping": {"start": 101, "length": 134, "filename": "tests/controlled_delegatecall.sol", "lines": [8, 9, 10, 11]}, "contract": {"name": "C", "source_mapping": {"start": 0, "length": 585, "filename": "tests/controlled_delegatecall.sol", "lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]}}}, "expressions": [{"expression": "addr_bad.delegatecall(data)", "source_mapping": {"start": 201, "length": 27, "filename": "tests/controlled_delegatecall.sol", "lines": [10]}}]}, {"check": "controlled-delegatecall", "impact": "High", "confidence": "Medium", "description": "C.bad_delegate_call2 (tests/controlled_delegatecall.sol#18-20) uses delegatecall to a input-controlled function id\n\taddr_bad.delegatecall(abi.encode(func_id,data)) (tests/controlled_delegatecall.sol#19)\n", "function": {"name": "bad_delegate_call2", "source_mapping": {"start": 337, "length": 118, "filename": "tests/controlled_delegatecall.sol", "lines": [18, 19, 20]}, "contract": {"name": "C", "source_mapping": {"start": 0, "length": 585, "filename": "tests/controlled_delegatecall.sol", "lines": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]}}}, "expressions": [{"expression": "addr_bad.delegatecall(abi.encode(func_id,data))", "source_mapping": {"start": 400, "length": 48, "filename": "tests/controlled_delegatecall.sol", "lines": [19]}}]}] \ No newline at end of file diff --git a/tests/expected_json/external_function.external-function.json b/tests/expected_json/external_function.external-function.json index ee86acf8f..a778dbfbd 100644 --- a/tests/expected_json/external_function.external-function.json +++ b/tests/expected_json/external_function.external-function.json @@ -1 +1 @@ -[{"check": "external-function", "impact": "Informational", "confidence": "High", "description": "ContractWithFunctionNotCalled.funcNotCalled3 (tests/external_function.sol#13-15) should be declared external\n", "function": {"name": "funcNotCalled3", "source_mapping": {"start": 257, "length": 41, "filename": "tests/external_function.sol", "lines": [13, 14, 15]}, "contract": {"name": "ContractWithFunctionNotCalled", "source_mapping": {"start": 211, "length": 258, "filename": "tests/external_function.sol", "lines": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]}}}}, {"check": "external-function", "impact": "Informational", "confidence": "High", "description": "ContractWithFunctionNotCalled.funcNotCalled2 (tests/external_function.sol#17-19) should be declared external\n", "function": {"name": "funcNotCalled2", "source_mapping": {"start": 304, "length": 41, "filename": "tests/external_function.sol", "lines": [17, 18, 19]}, "contract": {"name": "ContractWithFunctionNotCalled", "source_mapping": {"start": 211, "length": 258, "filename": "tests/external_function.sol", "lines": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]}}}}, {"check": "external-function", "impact": "Informational", "confidence": "High", "description": "ContractWithFunctionNotCalled.funcNotCalled (tests/external_function.sol#21-23) should be declared external\n", "function": {"name": "funcNotCalled", "source_mapping": {"start": 351, "length": 40, "filename": "tests/external_function.sol", "lines": [21, 22, 23]}, "contract": {"name": "ContractWithFunctionNotCalled", "source_mapping": {"start": 211, "length": 258, "filename": "tests/external_function.sol", "lines": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]}}}}, {"check": "external-function", "impact": "Informational", "confidence": "High", "description": "ContractWithFunctionNotCalled2.funcNotCalled (tests/external_function.sol#32-39) should be declared external\n", "function": {"name": "funcNotCalled", "source_mapping": {"start": 552, "length": 304, "filename": "tests/external_function.sol", "lines": [32, 33, 34, 35, 36, 37, 38, 39]}, "contract": {"name": "ContractWithFunctionNotCalled2", "source_mapping": {"start": 471, "length": 387, "filename": "tests/external_function.sol", "lines": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40]}}}}] \ No newline at end of file +[{"check": "external-function", "impact": "Informational", "confidence": "High", "description": "ContractWithFunctionNotCalled.funcNotCalled3 (tests/external_function.sol#13-15) should be declared external\n", "function": {"name": "funcNotCalled3", "source_mapping": {"start": 259, "length": 41, "filename": "tests/external_function.sol", "lines": [13, 14, 15]}, "contract": {"name": "ContractWithFunctionNotCalled", "source_mapping": {"start": 213, "length": 258, "filename": "tests/external_function.sol", "lines": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]}}}}, {"check": "external-function", "impact": "Informational", "confidence": "High", "description": "ContractWithFunctionNotCalled.funcNotCalled2 (tests/external_function.sol#17-19) should be declared external\n", "function": {"name": "funcNotCalled2", "source_mapping": {"start": 306, "length": 41, "filename": "tests/external_function.sol", "lines": [17, 18, 19]}, "contract": {"name": "ContractWithFunctionNotCalled", "source_mapping": {"start": 213, "length": 258, "filename": "tests/external_function.sol", "lines": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]}}}}, {"check": "external-function", "impact": "Informational", "confidence": "High", "description": "ContractWithFunctionNotCalled.funcNotCalled (tests/external_function.sol#21-23) should be declared external\n", "function": {"name": "funcNotCalled", "source_mapping": {"start": 353, "length": 40, "filename": "tests/external_function.sol", "lines": [21, 22, 23]}, "contract": {"name": "ContractWithFunctionNotCalled", "source_mapping": {"start": 213, "length": 258, "filename": "tests/external_function.sol", "lines": [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]}}}}, {"check": "external-function", "impact": "Informational", "confidence": "High", "description": "ContractWithFunctionNotCalled2.funcNotCalled (tests/external_function.sol#32-39) should be declared external\n", "function": {"name": "funcNotCalled", "source_mapping": {"start": 554, "length": 325, "filename": "tests/external_function.sol", "lines": [32, 33, 34, 35, 36, 37, 38, 39]}, "contract": {"name": "ContractWithFunctionNotCalled2", "source_mapping": {"start": 473, "length": 408, "filename": "tests/external_function.sol", "lines": [31, 32, 33, 34, 35, 36, 37, 38, 39, 40]}}}}] \ No newline at end of file diff --git a/tests/expected_json/inline_assembly_contract-0.5.1.assembly.json b/tests/expected_json/inline_assembly_contract-0.5.1.assembly.json new file mode 100644 index 000000000..903101b30 --- /dev/null +++ b/tests/expected_json/inline_assembly_contract-0.5.1.assembly.json @@ -0,0 +1 @@ +[{"check": "assembly", "impact": "Informational", "confidence": "High", "description": "GetCode.at uses assembly (tests/inline_assembly_contract-0.5.1.sol#6-20)\n\t- tests/inline_assembly_contract-0.5.1.sol#7-20\n", "function": {"name": "at", "source_mapping": {"start": 119, "length": 707, "filename": "tests/inline_assembly_contract-0.5.1.sol", "lines": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]}, "contract": {"name": "GetCode", "source_mapping": {"start": 97, "length": 731, "filename": "tests/inline_assembly_contract-0.5.1.sol", "lines": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]}}}, "assembly": [{"source_mapping": {"start": 198, "length": 628, "filename": "tests/inline_assembly_contract-0.5.1.sol", "lines": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]}}]}] \ No newline at end of file diff --git a/tests/expected_json/inline_assembly_library-0.5.1.assembly.json b/tests/expected_json/inline_assembly_library-0.5.1.assembly.json new file mode 100644 index 000000000..0d7798c65 --- /dev/null +++ b/tests/expected_json/inline_assembly_library-0.5.1.assembly.json @@ -0,0 +1 @@ +[{"check": "assembly", "impact": "Informational", "confidence": "High", "description": "VectorSum.sumAsm uses assembly (tests/inline_assembly_library-0.5.1.sol#16-22)\n\t- tests/inline_assembly_library-0.5.1.sol#18-21\n", "function": {"name": "sumAsm", "source_mapping": {"start": 599, "length": 254, "filename": "tests/inline_assembly_library-0.5.1.sol", "lines": [16, 17, 18, 19, 20, 21, 22]}, "contract": {"name": "VectorSum", "source_mapping": {"start": 97, "length": 1602, "filename": "tests/inline_assembly_library-0.5.1.sol", "lines": [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]}}}, "assembly": [{"source_mapping": {"start": 733, "length": 114, "filename": "tests/inline_assembly_library-0.5.1.sol", "lines": [18, 19, 20, 21]}}]}, {"check": "assembly", "impact": "Informational", "confidence": "High", "description": "VectorSum.sumPureAsm uses assembly (tests/inline_assembly_library-0.5.1.sol#25-47)\n\t- tests/inline_assembly_library-0.5.1.sol#26-47\n", "function": {"name": "sumPureAsm", "source_mapping": {"start": 936, "length": 761, "filename": "tests/inline_assembly_library-0.5.1.sol", "lines": [25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]}, "contract": {"name": "VectorSum", "source_mapping": {"start": 97, "length": 1602, "filename": "tests/inline_assembly_library-0.5.1.sol", "lines": [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]}}}, "assembly": [{"source_mapping": {"start": 1020, "length": 677, "filename": "tests/inline_assembly_library-0.5.1.sol", "lines": [26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]}}]}] \ No newline at end of file diff --git a/tests/expected_json/locked_ether-0.5.1.locked-ether.json b/tests/expected_json/locked_ether-0.5.1.locked-ether.json new file mode 100644 index 000000000..d5a375899 --- /dev/null +++ b/tests/expected_json/locked_ether-0.5.1.locked-ether.json @@ -0,0 +1 @@ +[{"check": "locked-ether", "impact": "Medium", "confidence": "High", "description": "Contract locking ether found in tests/locked_ether-0.5.1.sol:\n\tContract OnlyLocked has payable functions:\n\t - receive (tests/locked_ether-0.5.1.sol#4-6)\n\tBut has not function to withdraw the ether\n", "functions": [{"name": "receive", "source_mapping": {"start": 46, "length": 72, "filename": "tests/locked_ether-0.5.1.sol", "lines": [4, 5, 6]}, "contract": {"name": "Locked", "source_mapping": {"start": 24, "length": 97, "filename": "tests/locked_ether-0.5.1.sol", "lines": [2, 3, 4, 5, 6, 7, 8]}}}], "contract": {"name": "OnlyLocked", "source_mapping": {"start": 375, "length": 32, "filename": "tests/locked_ether-0.5.1.sol", "lines": [26]}}}] \ No newline at end of file diff --git a/tests/expected_json/locked_ether.locked-ether.json b/tests/expected_json/locked_ether.locked-ether.json index 0637a088a..2a2c04e1e 100644 --- a/tests/expected_json/locked_ether.locked-ether.json +++ b/tests/expected_json/locked_ether.locked-ether.json @@ -1 +1 @@ -[] \ No newline at end of file +[{"check": "locked-ether", "impact": "Medium", "confidence": "High", "description": "Contract locking ether found in tests/locked_ether.sol:\n\tContract OnlyLocked has payable functions:\n\t - receive (tests/locked_ether.sol#4-6)\n\tBut has not function to withdraw the ether\n", "functions": [{"name": "receive", "source_mapping": {"start": 47, "length": 72, "filename": "tests/locked_ether.sol", "lines": [4, 5, 6]}, "contract": {"name": "Locked", "source_mapping": {"start": 25, "length": 97, "filename": "tests/locked_ether.sol", "lines": [2, 3, 4, 5, 6, 7, 8]}}}], "contract": {"name": "OnlyLocked", "source_mapping": {"start": 368, "length": 32, "filename": "tests/locked_ether.sol", "lines": [26]}}}] \ No newline at end of file diff --git a/tests/expected_json/low_level_calls.low-level-calls.json b/tests/expected_json/low_level_calls.low-level-calls.json index a0c088a76..edf30d574 100644 --- a/tests/expected_json/low_level_calls.low-level-calls.json +++ b/tests/expected_json/low_level_calls.low-level-calls.json @@ -1 +1 @@ -[{"check": "low-level-calls", "impact": "Informational", "confidence": "High", "description": "Low level call in Sender.send (tests/low_level_calls.sol#5-7):\n\t-_receiver.call.value(msg.value).gas(7777)() tests/low_level_calls.sol#6\n", "function": {"name": "send", "source_mapping": {"start": 49, "length": 101, "filename": "tests/low_level_calls.sol", "lines": [5, 6, 7]}, "contract": {"name": "Sender", "source_mapping": {"start": 27, "length": 125, "filename": "tests/low_level_calls.sol", "lines": [4, 5, 6, 7, 8]}}}, "expressions": [{"expression": "_receiver.call.value(msg.value).gas(7777)()", "source_mapping": {"start": 100, "length": 43, "filename": "tests/low_level_calls.sol", "lines": [6]}}]}] \ No newline at end of file +[{"check": "low-level-calls", "impact": "Informational", "confidence": "High", "description": "Low level call in Sender.send (tests/low_level_calls.sol#5-7):\n\t-_receiver.call.value(msg.value).gas(7777)() tests/low_level_calls.sol#6\n", "function": {"name": "send", "source_mapping": {"start": 51, "length": 112, "filename": "tests/low_level_calls.sol", "lines": [5, 6, 7]}, "contract": {"name": "Sender", "source_mapping": {"start": 29, "length": 136, "filename": "tests/low_level_calls.sol", "lines": [4, 5, 6, 7, 8]}}}, "expressions": [{"expression": "_receiver.call.value(msg.value).gas(7777)()", "source_mapping": {"start": 111, "length": 45, "filename": "tests/low_level_calls.sol", "lines": [6]}}]}] \ No newline at end of file diff --git a/tests/expected_json/naming_convention.naming-convention.json b/tests/expected_json/naming_convention.naming-convention.json index c688066ff..6bab6a8e6 100644 --- a/tests/expected_json/naming_convention.naming-convention.json +++ b/tests/expected_json/naming_convention.naming-convention.json @@ -1 +1 @@ -[{"check": "naming-convention", "type": "contract", "convention": "CapWords", "name": {"name": "naming", "source_mapping": {"start": 26, "length": 598, "filename": "tests/naming_convention.sol", "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]}}}, {"check": "naming-convention", "type": "structure", "convention": "CapWords", "name": {"name": "test", "source_mapping": {"start": 227, "length": 20, "filename": "tests/naming_convention.sol", "lines": [14, 15, 16]}}}, {"check": "naming-convention", "type": "event", "convention": "CapWords", "name": {"name": "event_", "source_mapping": {"start": 303, "length": 19, "filename": "tests/naming_convention.sol", "lines": [23]}}}, {"check": "naming-convention", "type": "function", "convention": "mixedCase", "name": {"name": "GetOne", "source_mapping": {"start": 405, "length": 71, "filename": "tests/naming_convention.sol", "lines": [30, 31, 32, 33]}}}, {"check": "naming-convention", "type": "parameter", "convention": "mixedCase", "name": {"name": "Number2", "source_mapping": {"start": 512, "length": 12, "filename": "tests/naming_convention.sol", "lines": [35]}}}, {"check": "naming-convention", "type": "variable_constant", "convention": "UPPER_CASE_WITH_UNDERSCORES", "name": {"name": "MY_other_CONSTANT", "source_mapping": {"start": 141, "length": 35, "filename": "tests/naming_convention.sol", "lines": [9]}}}, {"check": "naming-convention", "type": "variable", "convention": "mixedCase", "name": {"name": "Var_One", "source_mapping": {"start": 183, "length": 16, "filename": "tests/naming_convention.sol", "lines": [11]}}}, {"check": "naming-convention", "type": "enum", "convention": "CapWords", "name": {"name": "numbers", "source_mapping": {"start": 77, "length": 23, "filename": "tests/naming_convention.sol", "lines": [6]}}}, {"check": "naming-convention", "type": "modifier", "convention": "mixedCase", "name": {"name": "CantDo", "source_mapping": {"start": 545, "length": 36, "filename": "tests/naming_convention.sol", "lines": [41, 42, 43]}}}, {"check": "naming-convention", "type": "parameter", "convention": "mixedCase", "name": {"name": "_used", "source_mapping": {"start": 748, "length": 10, "filename": "tests/naming_convention.sol", "lines": [59]}}}, {"check": "naming-convention", "type": "variable", "convention": "mixedCase", "name": {"name": "_myPublicVar", "source_mapping": {"start": 695, "length": 17, "filename": "tests/naming_convention.sol", "lines": [56]}}}, {"check": "naming-convention", "type": "variable", "convention": "l_O_I_should_not_be_used", "name": {"name": "l", "source_mapping": {"start": 847, "length": 10, "filename": "tests/naming_convention.sol", "lines": [67]}}}] \ No newline at end of file +[{"check": "naming-convention", "type": "contract", "convention": "CapWords", "name": {"name": "naming", "source_mapping": {"start": 28, "length": 642, "filename": "tests/naming_convention.sol", "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]}}}, {"check": "naming-convention", "type": "structure", "convention": "CapWords", "name": {"name": "test", "source_mapping": {"start": 229, "length": 35, "filename": "tests/naming_convention.sol", "lines": [14, 15, 16]}}}, {"check": "naming-convention", "type": "event", "convention": "CapWords", "name": {"name": "event_", "source_mapping": {"start": 335, "length": 19, "filename": "tests/naming_convention.sol", "lines": [23]}}}, {"check": "naming-convention", "type": "function", "convention": "mixedCase", "name": {"name": "GetOne", "source_mapping": {"start": 440, "length": 75, "filename": "tests/naming_convention.sol", "lines": [30, 31, 32, 33]}}}, {"check": "naming-convention", "type": "parameter", "convention": "mixedCase", "name": {"name": "Number2", "source_mapping": {"start": 551, "length": 12, "filename": "tests/naming_convention.sol", "lines": [35]}}}, {"check": "naming-convention", "type": "variable_constant", "convention": "UPPER_CASE_WITH_UNDERSCORES", "name": {"name": "MY_other_CONSTANT", "source_mapping": {"start": 143, "length": 35, "filename": "tests/naming_convention.sol", "lines": [9]}}}, {"check": "naming-convention", "type": "variable", "convention": "mixedCase", "name": {"name": "Var_One", "source_mapping": {"start": 185, "length": 16, "filename": "tests/naming_convention.sol", "lines": [11]}}}, {"check": "naming-convention", "type": "enum", "convention": "CapWords", "name": {"name": "numbers", "source_mapping": {"start": 79, "length": 23, "filename": "tests/naming_convention.sol", "lines": [6]}}}, {"check": "naming-convention", "type": "modifier", "convention": "mixedCase", "name": {"name": "CantDo", "source_mapping": {"start": 591, "length": 36, "filename": "tests/naming_convention.sol", "lines": [41, 42, 43]}}}, {"check": "naming-convention", "type": "parameter", "convention": "mixedCase", "name": {"name": "_used", "source_mapping": {"start": 794, "length": 10, "filename": "tests/naming_convention.sol", "lines": [59]}}}, {"check": "naming-convention", "type": "variable", "convention": "mixedCase", "name": {"name": "_myPublicVar", "source_mapping": {"start": 741, "length": 17, "filename": "tests/naming_convention.sol", "lines": [56]}}}, {"check": "naming-convention", "type": "variable", "convention": "l_O_I_should_not_be_used", "name": {"name": "l", "source_mapping": {"start": 900, "length": 10, "filename": "tests/naming_convention.sol", "lines": [67]}}}] \ No newline at end of file diff --git a/tests/expected_json/reentrancy-0.5.1.reentrancy.json b/tests/expected_json/reentrancy-0.5.1.reentrancy.json new file mode 100644 index 000000000..e57f9b986 --- /dev/null +++ b/tests/expected_json/reentrancy-0.5.1.reentrancy.json @@ -0,0 +1 @@ +[{"check": "reentrancy", "impact": "High", "confidence": "Medium", "description": "Reentrancy in Reentrancy.withdrawBalance (tests/reentrancy-0.5.1.sol#14-22):\n\tExternal calls:\n\t- (ret,mem) = msg.sender.call.value(userBalance[msg.sender])() (tests/reentrancy-0.5.1.sol#17)\n\tState variables written after the call(s):\n\t- userBalance (tests/reentrancy-0.5.1.sol#21)\n", "function": {"name": "withdrawBalance", "source_mapping": {"start": 298, "length": 357, "filename": "tests/reentrancy-0.5.1.sol", "lines": [14, 15, 16, 17, 18, 19, 20, 21, 22]}, "contract": {"name": "Reentrancy", "source_mapping": {"start": 25, "length": 1807, "filename": "tests/reentrancy-0.5.1.sol", "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]}}}, "external_calls": [{"expression": "(ret,mem) = msg.sender.call.value(userBalance[msg.sender])()", "source_mapping": {"start": 477, "length": 81, "filename": "tests/reentrancy-0.5.1.sol", "lines": [17]}}], "external_calls_sending_eth": [], "variables_written": [{"name": "userBalance", "expression": "userBalance[msg.sender] = 0", "source_mapping": {"start": 621, "length": 27, "filename": "tests/reentrancy-0.5.1.sol", "lines": [21]}}]}, {"check": "reentrancy", "impact": "High", "confidence": "Medium", "description": "Reentrancy in Reentrancy.withdrawBalance_fixed_3 (tests/reentrancy-0.5.1.sol#44-53):\n\tExternal calls:\n\t- (ret,mem) = msg.sender.call.value(amount)() (tests/reentrancy-0.5.1.sol#49)\n\tState variables written after the call(s):\n\t- userBalance (tests/reentrancy-0.5.1.sol#51)\n", "function": {"name": "withdrawBalance_fixed_3", "source_mapping": {"start": 1434, "length": 393, "filename": "tests/reentrancy-0.5.1.sol", "lines": [44, 45, 46, 47, 48, 49, 50, 51, 52, 53]}, "contract": {"name": "Reentrancy", "source_mapping": {"start": 25, "length": 1807, "filename": "tests/reentrancy-0.5.1.sol", "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]}}}, "external_calls": [{"expression": "(ret,mem) = msg.sender.call.value(amount)()", "source_mapping": {"start": 1679, "length": 64, "filename": "tests/reentrancy-0.5.1.sol", "lines": [49]}}], "external_calls_sending_eth": [], "variables_written": [{"name": "userBalance", "expression": "userBalance[msg.sender] = amount", "source_mapping": {"start": 1778, "length": 32, "filename": "tests/reentrancy-0.5.1.sol", "lines": [51]}}]}] \ No newline at end of file diff --git a/tests/expected_json/tx_origin-0.5.1.tx-origin.json b/tests/expected_json/tx_origin-0.5.1.tx-origin.json new file mode 100644 index 000000000..1fd791145 --- /dev/null +++ b/tests/expected_json/tx_origin-0.5.1.tx-origin.json @@ -0,0 +1 @@ +[{"check": "tx-origin", "impact": "Medium", "confidence": "Medium", "description": "TxOrigin.bug0 uses tx.origin for authorization:\n\t- require(bool)(tx.origin == owner) (tests/tx_origin-0.5.1.sol#10)\n", "function": {"name": "bug0", "source_mapping": {"start": 127, "length": 66, "filename": "tests/tx_origin-0.5.1.sol", "lines": [9, 10, 11]}, "contract": {"name": "TxOrigin", "source_mapping": {"start": 25, "length": 442, "filename": "tests/tx_origin-0.5.1.sol", "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]}}}, "expressions": [{"expression": "require(bool)(tx.origin == owner)", "source_mapping": {"start": 159, "length": 27, "filename": "tests/tx_origin-0.5.1.sol", "lines": [10]}}]}, {"check": "tx-origin", "impact": "Medium", "confidence": "Medium", "description": "TxOrigin.bug2 uses tx.origin for authorization:\n\t- tx.origin != owner (tests/tx_origin-0.5.1.sol#14-16)\n", "function": {"name": "bug2", "source_mapping": {"start": 199, "length": 95, "filename": "tests/tx_origin-0.5.1.sol", "lines": [13, 14, 15, 16, 17]}, "contract": {"name": "TxOrigin", "source_mapping": {"start": 25, "length": 442, "filename": "tests/tx_origin-0.5.1.sol", "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]}}}, "expressions": [{"expression": "tx.origin != owner", "source_mapping": {"start": 231, "length": 57, "filename": "tests/tx_origin-0.5.1.sol", "lines": [14, 15, 16]}}]}] \ No newline at end of file diff --git a/tests/expected_json/tx_origin.tx-origin.json b/tests/expected_json/tx_origin.tx-origin.json index b8e6ecb4b..7d5775a47 100644 --- a/tests/expected_json/tx_origin.tx-origin.json +++ b/tests/expected_json/tx_origin.tx-origin.json @@ -1 +1 @@ -[{"check": "tx-origin", "impact": "Medium", "confidence": "Medium", "description": "TxOrigin.bug0 uses tx.origin for authorization:\n\t- require(bool)(tx.origin == owner) (tests/tx_origin.sol#10)\n", "function": {"name": "bug0", "source_mapping": {"start": 114, "length": 60, "filename": "tests/tx_origin.sol", "lines": [9, 10, 11]}, "contract": {"name": "TxOrigin", "source_mapping": {"start": 26, "length": 393, "filename": "tests/tx_origin.sol", "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]}}}, "expressions": [{"expression": "require(bool)(tx.origin == owner)", "source_mapping": {"start": 140, "length": 27, "filename": "tests/tx_origin.sol", "lines": [10]}}]}, {"check": "tx-origin", "impact": "Medium", "confidence": "Medium", "description": "TxOrigin.bug2 uses tx.origin for authorization:\n\t- tx.origin != owner (tests/tx_origin.sol#14-16)\n", "function": {"name": "bug2", "source_mapping": {"start": 180, "length": 89, "filename": "tests/tx_origin.sol", "lines": [13, 14, 15, 16, 17]}, "contract": {"name": "TxOrigin", "source_mapping": {"start": 26, "length": 393, "filename": "tests/tx_origin.sol", "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]}}}, "expressions": [{"expression": "tx.origin != owner", "source_mapping": {"start": 206, "length": 57, "filename": "tests/tx_origin.sol", "lines": [14, 15, 16]}}]}] \ No newline at end of file +[{"check": "tx-origin", "impact": "Medium", "confidence": "Medium", "description": "TxOrigin.bug0 uses tx.origin for authorization:\n\t- require(bool)(tx.origin == owner) (tests/tx_origin.sol#10)\n", "function": {"name": "bug0", "source_mapping": {"start": 116, "length": 60, "filename": "tests/tx_origin.sol", "lines": [9, 10, 11]}, "contract": {"name": "TxOrigin", "source_mapping": {"start": 28, "length": 393, "filename": "tests/tx_origin.sol", "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]}}}, "expressions": [{"expression": "require(bool)(tx.origin == owner)", "source_mapping": {"start": 142, "length": 27, "filename": "tests/tx_origin.sol", "lines": [10]}}]}, {"check": "tx-origin", "impact": "Medium", "confidence": "Medium", "description": "TxOrigin.bug2 uses tx.origin for authorization:\n\t- tx.origin != owner (tests/tx_origin.sol#14-16)\n", "function": {"name": "bug2", "source_mapping": {"start": 182, "length": 89, "filename": "tests/tx_origin.sol", "lines": [13, 14, 15, 16, 17]}, "contract": {"name": "TxOrigin", "source_mapping": {"start": 28, "length": 393, "filename": "tests/tx_origin.sol", "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]}}}, "expressions": [{"expression": "tx.origin != owner", "source_mapping": {"start": 208, "length": 57, "filename": "tests/tx_origin.sol", "lines": [14, 15, 16]}}]}] \ No newline at end of file diff --git a/tests/expected_json/uninitialized-0.5.1.uninitialized-state.json b/tests/expected_json/uninitialized-0.5.1.uninitialized-state.json new file mode 100644 index 000000000..956bed27a --- /dev/null +++ b/tests/expected_json/uninitialized-0.5.1.uninitialized-state.json @@ -0,0 +1 @@ +[{"check": "uninitialized-state", "impact": "High", "confidence": "High", "description": "Uninitialized.destination (tests/uninitialized-0.5.1.sol#5) is never initialized. It is used in:\n\t- transfer (tests/uninitialized-0.5.1.sol#7-9)\n", "variable": {"name": "destination", "source_mapping": {"start": 54, "length": 27, "filename": "tests/uninitialized-0.5.1.sol", "lines": [5]}}, "functions": [{"name": "transfer", "source_mapping": {"start": 88, "length": 82, "filename": "tests/uninitialized-0.5.1.sol", "lines": [7, 8, 9]}, "contract": {"name": "Uninitialized", "source_mapping": {"start": 25, "length": 148, "filename": "tests/uninitialized-0.5.1.sol", "lines": [3, 4, 5, 6, 7, 8, 9, 10, 11]}}}]}, {"check": "uninitialized-state", "impact": "High", "confidence": "High", "description": "Test.balances (tests/uninitialized-0.5.1.sol#15) is never initialized. It is used in:\n\t- use (tests/uninitialized-0.5.1.sol#23-26)\n", "variable": {"name": "balances", "source_mapping": {"start": 196, "length": 34, "filename": "tests/uninitialized-0.5.1.sol", "lines": [15]}}, "functions": [{"name": "use", "source_mapping": {"start": 369, "length": 154, "filename": "tests/uninitialized-0.5.1.sol", "lines": [23, 24, 25, 26]}, "contract": {"name": "Test", "source_mapping": {"start": 176, "length": 349, "filename": "tests/uninitialized-0.5.1.sol", "lines": [14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27]}}}]}, {"check": "uninitialized-state", "impact": "High", "confidence": "High", "description": "Test2.st (tests/uninitialized-0.5.1.sol#45) is never initialized. It is used in:\n\t- use (tests/uninitialized-0.5.1.sol#53-56)\n", "variable": {"name": "st", "source_mapping": {"start": 726, "length": 15, "filename": "tests/uninitialized-0.5.1.sol", "lines": [45]}}, "functions": [{"name": "use", "source_mapping": {"start": 913, "length": 129, "filename": "tests/uninitialized-0.5.1.sol", "lines": [53, 54, 55, 56]}, "contract": {"name": "Test2", "source_mapping": {"start": 672, "length": 373, "filename": "tests/uninitialized-0.5.1.sol", "lines": [42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58]}}}]}, {"check": "uninitialized-state", "impact": "High", "confidence": "High", "description": "Test2.v (tests/uninitialized-0.5.1.sol#47) is never initialized. It is used in:\n\t- init (tests/uninitialized-0.5.1.sol#49-51)\n", "variable": {"name": "v", "source_mapping": {"start": 779, "length": 6, "filename": "tests/uninitialized-0.5.1.sol", "lines": [47]}}, "functions": [{"name": "init", "source_mapping": {"start": 848, "length": 59, "filename": "tests/uninitialized-0.5.1.sol", "lines": [49, 50, 51]}, "contract": {"name": "Test2", "source_mapping": {"start": 672, "length": 373, "filename": "tests/uninitialized-0.5.1.sol", "lines": [42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58]}}}]}] \ No newline at end of file diff --git a/tests/expected_json/unused_return.unused-return.json b/tests/expected_json/unused_return.unused-return.json index 3f09690a2..49ad2b1ae 100644 --- a/tests/expected_json/unused_return.unused-return.json +++ b/tests/expected_json/unused_return.unused-return.json @@ -1 +1 @@ -[{"check": "unused-return", "impact": "Medium", "confidence": "Medium", "description": "User.test (tests/unused_return.sol#17-29) does not use the value returned by external calls:\n\t-t.f() (tests/unused_return.sol#18)\n\t-a.add(0) (tests/unused_return.sol#22)\n", "function": {"name": "test", "source_mapping": {"start": 230, "length": 347, "filename": "tests/unused_return.sol", "lines": [17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]}, "contract": {"name": "User", "source_mapping": {"start": 180, "length": 399, "filename": "tests/unused_return.sol", "lines": [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]}}}, "expressions": [{"expression": "t.f()", "source_mapping": {"start": 263, "length": 5, "filename": "tests/unused_return.sol", "lines": [18]}}, {"expression": "a.add(0)", "source_mapping": {"start": 337, "length": 8, "filename": "tests/unused_return.sol", "lines": [22]}}]}] \ No newline at end of file +[{"check": "unused-return", "impact": "Medium", "confidence": "Medium", "description": "User.test (tests/unused_return.sol#17-29) does not use the value returned by external calls:\n\t-t.f() (tests/unused_return.sol#18)\n\t-a.add(0) (tests/unused_return.sol#22)\n", "function": {"name": "test", "source_mapping": {"start": 239, "length": 354, "filename": "tests/unused_return.sol", "lines": [17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]}, "contract": {"name": "User", "source_mapping": {"start": 189, "length": 406, "filename": "tests/unused_return.sol", "lines": [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]}}}, "expressions": [{"expression": "t.f()", "source_mapping": {"start": 279, "length": 5, "filename": "tests/unused_return.sol", "lines": [18]}}, {"expression": "a.add(0)", "source_mapping": {"start": 353, "length": 8, "filename": "tests/unused_return.sol", "lines": [22]}}]}] \ No newline at end of file diff --git a/tests/expected_json/unused_state.unused-state.json b/tests/expected_json/unused_state.unused-state.json index ba8c1fee3..304c0970d 100644 --- a/tests/expected_json/unused_state.unused-state.json +++ b/tests/expected_json/unused_state.unused-state.json @@ -1 +1 @@ -[{"check": "unused-state", "impact": "Informational", "confidence": "High", "description": "A.unused (tests/unused_state.sol#4) is never used in B\n", "variables": [{"name": "unused", "source_mapping": {"start": 42, "length": 14, "filename": "tests/unused_state.sol", "lines": [4]}}]}] \ No newline at end of file +[{"check": "unused-state", "impact": "Informational", "confidence": "High", "description": "A.unused (tests/unused_state.sol#4) is never used in B\n", "variables": [{"name": "unused", "source_mapping": {"start": 44, "length": 14, "filename": "tests/unused_state.sol", "lines": [4]}}]}] \ No newline at end of file diff --git a/tests/external_function.sol b/tests/external_function.sol index 040bb9329..714e6997f 100644 --- a/tests/external_function.sol +++ b/tests/external_function.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +//pragma solidity ^0.4.24; import "./external_function_test_2.sol"; @@ -31,8 +31,8 @@ contract ContractWithFunctionNotCalled { contract ContractWithFunctionNotCalled2 is ContractWithFunctionCalledSuper { function funcNotCalled() public { uint256 i = 0; - address three = new ContractWithFunctionNotCalled(); - three.call(bytes4(keccak256("helloTwo()"))); + address three = address(new ContractWithFunctionNotCalled()); + three.call(abi.encode(bytes4(keccak256("helloTwo()")))); super.callWithSuper(); ContractWithFunctionCalled c = new ContractWithFunctionCalled(); c.funcCalled(); diff --git a/tests/external_function_test_2.sol b/tests/external_function_test_2.sol index 406494631..ae7388993 100644 --- a/tests/external_function_test_2.sol +++ b/tests/external_function_test_2.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +//pragma solidity ^0.4.24; contract ContractWithFunctionCalled { function funcCalled() external { diff --git a/tests/inline_assembly_contract-0.5.1.sol b/tests/inline_assembly_contract-0.5.1.sol new file mode 100644 index 000000000..3f06c4ea9 --- /dev/null +++ b/tests/inline_assembly_contract-0.5.1.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.5.1; + +// taken from https://solidity.readthedocs.io/en/v0.4.25/assembly.html + +library GetCode { + function at(address _addr) public view returns (bytes memory o_code) { + assembly { + // retrieve the size of the code, this needs assembly + let size := extcodesize(_addr) + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + o_code := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(o_code, size) + // actually retrieve the code, this needs assembly + extcodecopy(_addr, add(o_code, 0x20), 0, size) + } + } +} + diff --git a/tests/inline_assembly_library-0.5.1.sol b/tests/inline_assembly_library-0.5.1.sol new file mode 100644 index 000000000..93624538e --- /dev/null +++ b/tests/inline_assembly_library-0.5.1.sol @@ -0,0 +1,49 @@ +pragma solidity ^0.5.1; + +// taken from https://solidity.readthedocs.io/en/v0.4.25/assembly.html + +library VectorSum { + // This function is less efficient because the optimizer currently fails to + // remove the bounds checks in array access. + function sumSolidity(uint[] memory _data) public view returns (uint o_sum) { + for (uint i = 0; i < _data.length; ++i) + o_sum += _data[i]; + } + + // We know that we only access the array in bounds, so we can avoid the check. + // 0x20 needs to be added to an array because the first slot contains the + // array length. + function sumAsm(uint[] memory _data) public view returns (uint o_sum) { + for (uint i = 0; i < _data.length; ++i) { + assembly { + o_sum := add(o_sum, mload(add(add(_data, 0x20), mul(i, 0x20)))) + } + } + } + + // Same as above, but accomplish the entire code within inline assembly. + function sumPureAsm(uint[] memory _data) public view returns (uint o_sum) { + assembly { + // Load the length (first 32 bytes) + let len := mload(_data) + + // Skip over the length field. + // + // Keep temporary variable so it can be incremented in place. + // + // NOTE: incrementing _data would result in an unusable + // _data variable after this assembly block + let data := add(_data, 0x20) + + // Iterate until the bound is not met. + for + { let end := add(data, len) } + lt(data, end) + { data := add(data, 0x20) } + { + o_sum := add(o_sum, mload(data)) + } + } + } +} + diff --git a/tests/locked_ether-0.5.1.sol b/tests/locked_ether-0.5.1.sol new file mode 100644 index 000000000..0269ce855 --- /dev/null +++ b/tests/locked_ether-0.5.1.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.5.0; +contract Locked{ + + function receive() payable public{ + require(msg.value > 0); + } + +} + +contract Send{ + address payable owner = msg.sender; + + function withdraw() public{ + owner.transfer(address(this).balance); + } +} + +contract Unlocked is Locked, Send{ + + function withdraw() public{ + super.withdraw(); + } + +} + +contract OnlyLocked is Locked{ } diff --git a/tests/low_level_calls.sol b/tests/low_level_calls.sol index c5f1e2e46..45d732a54 100644 --- a/tests/low_level_calls.sol +++ b/tests/low_level_calls.sol @@ -1,9 +1,9 @@ -pragma solidity ^0.4.24; +//pragma solidity ^0.4.24; contract Sender { - function send(address _receiver) payable { - _receiver.call.value(msg.value).gas(7777)(); + function send(address _receiver) payable external { + _receiver.call.value(msg.value).gas(7777)(""); } } @@ -11,7 +11,7 @@ contract Sender { contract Receiver { uint public balance = 0; - function () payable { + function () payable external{ balance += msg.value; } -} \ No newline at end of file +} diff --git a/tests/naming_convention.sol b/tests/naming_convention.sol index f632aa69e..cc3596f6d 100644 --- a/tests/naming_convention.sol +++ b/tests/naming_convention.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +//pragma solidity ^0.4.24; contract naming { @@ -12,27 +12,27 @@ contract naming { uint varTwo = 2; struct test { - + uint a; } struct Test { - + uint a; } event Event_(uint); event event_(uint); - function getOne() constant returns (uint) + function getOne() view public returns(uint) { return 1; } - function GetOne() constant returns (uint) + function GetOne() view public returns (uint) { return 1; } - function setInt(uint number1, uint Number2) + function setInt(uint number1, uint Number2) public { } @@ -56,7 +56,7 @@ contract T { uint _myPublicVar; - function test(uint _unused, uint _used) returns(uint){ + function test(uint _unused, uint _used) public returns(uint){ return _used;} diff --git a/tests/tx_origin-0.5.1.sol b/tests/tx_origin-0.5.1.sol new file mode 100644 index 000000000..ecb72c1ad --- /dev/null +++ b/tests/tx_origin-0.5.1.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.5.0; + +contract TxOrigin { + + address payable owner; + + constructor() public{ owner = msg.sender; } + + function bug0() public{ + require(tx.origin == owner); + } + + function bug2() public{ + if (tx.origin != owner) { + revert(); + } + } + + function legit0() public{ + require(tx.origin == msg.sender); + } + + function legit1() public{ + tx.origin.transfer(address(this).balance); + } +} diff --git a/tests/tx_origin.sol b/tests/tx_origin.sol index 93bb5c757..8152c93be 100644 --- a/tests/tx_origin.sol +++ b/tests/tx_origin.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +//pragma solidity ^0.4.24; contract TxOrigin { diff --git a/tests/unused_return.sol b/tests/unused_return.sol index dab5ee766..d1c189598 100644 --- a/tests/unused_return.sol +++ b/tests/unused_return.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +//pragma solidity ^0.4.24; library SafeMath{ function add(uint a, uint b) public returns(uint){ @@ -7,14 +7,14 @@ library SafeMath{ } contract Target{ - function f() returns(uint); + function f() public returns(uint); } contract User{ using SafeMath for uint; - function test(Target t){ + function test(Target t) public{ t.f(); // example with library usage diff --git a/tests/unused_state.sol b/tests/unused_state.sol index 496457c79..1f4e7839c 100644 --- a/tests/unused_state.sol +++ b/tests/unused_state.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.4.24; +//pragma solidity ^0.4.24; contract A{ address unused; @@ -7,7 +7,7 @@ contract A{ contract B is A{ - function () public{ - used = 0; + function () external{ + used = address(0); } } From f7c1d2c5e75444a5fbd4bfec0d0e6533c08f4de5 Mon Sep 17 00:00:00 2001 From: Josselin Date: Tue, 11 Dec 2018 14:43:45 -0500 Subject: [PATCH 3/6] Update travis install --- scripts/travis_install.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/travis_install.sh b/scripts/travis_install.sh index cf45f33d8..a8f27af21 100755 --- a/scripts/travis_install.sh +++ b/scripts/travis_install.sh @@ -4,10 +4,10 @@ python setup.py install pip install deepdiff function install_solc { - sudo wget -O /usr/bin/solc https://github.com/ethereum/solidity/releases/download/v0.4.25/solc-static-linux - sudo chmod +x /usr/bin/solc-4.25 - sudo wget -O /usr/bin/solc https://github.com/ethereum/solidity/releases/download/v0.5.1/solc-static-linux - sudo chmod +x /usr/bin/solc-5.1 + sudo wget -O /usr/bin/solc-0.4.25 https://github.com/ethereum/solidity/releases/download/v0.4.25/solc-static-linux + sudo chmod +x /usr/bin/solc-0.4.25 + sudo wget -O /usr/bin/solc-0.5.1 https://github.com/ethereum/solidity/releases/download/v0.5.1/solc-static-linux + sudo chmod +x /usr/bin/solc-0.5.1 } install_solc From 1f90b4c7f1361a0c49905fe680f5142dd390b429 Mon Sep 17 00:00:00 2001 From: Josselin Date: Tue, 11 Dec 2018 14:50:41 -0500 Subject: [PATCH 4/6] Update travis scripts --- scripts/travis_install.sh | 2 ++ scripts/travis_test_4.sh | 18 +----------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/scripts/travis_install.sh b/scripts/travis_install.sh index a8f27af21..124527beb 100755 --- a/scripts/travis_install.sh +++ b/scripts/travis_install.sh @@ -8,6 +8,8 @@ function install_solc { sudo chmod +x /usr/bin/solc-0.4.25 sudo wget -O /usr/bin/solc-0.5.1 https://github.com/ethereum/solidity/releases/download/v0.5.1/solc-static-linux sudo chmod +x /usr/bin/solc-0.5.1 + + sudo cp /usr/bin/solc-0.5.1 /usr/bin/solc } install_solc diff --git a/scripts/travis_test_4.sh b/scripts/travis_test_4.sh index 57e1c85ac..976ee0ba6 100755 --- a/scripts/travis_test_4.sh +++ b/scripts/travis_test_4.sh @@ -88,20 +88,4 @@ test_slither tests/constant.sol "constant-function" test_slither tests/unused_return.sol "unused-return" -### Test scripts - -python examples/scripts/functions_called.py examples/scripts/functions_called.sol -if [ $? -ne 0 ]; then - exit 1 -fi - -python examples/scripts/functions_writing.py examples/scripts/functions_writing.sol -if [ $? -ne 0 ]; then - exit 1 -fi - -python examples/scripts/variable_in_condition.py examples/scripts/variable_in_condition.sol -if [ $? -ne 0 ]; then - exit 1 -fi -exit 0 + From 37c2ded097827de3973f6d368f777c624bf70ec8 Mon Sep 17 00:00:00 2001 From: Josselin Date: Tue, 11 Dec 2018 14:56:46 -0500 Subject: [PATCH 5/6] Add visibility to Solidity script examples --- examples/scripts/functions_called.sol | 10 +++++----- examples/scripts/functions_writing.sol | 4 ++-- examples/scripts/variable_in_condition.sol | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/scripts/functions_called.sol b/examples/scripts/functions_called.sol index 85d645e5d..aba749a49 100644 --- a/examples/scripts/functions_called.sol +++ b/examples/scripts/functions_called.sol @@ -1,6 +1,6 @@ contract BaseContract{ - function f1(){ + function f1() public{ } } @@ -9,21 +9,21 @@ contract Contract is BaseContract{ uint a; - function entry_point(){ + function entry_point() public{ f1(); f2(); } - function f1(){ + function f1() public{ super.f1(); } - function f2(){ + function f2() public{ } // not reached from entry_point - function f3(){ + function f3() public{ } } diff --git a/examples/scripts/functions_writing.sol b/examples/scripts/functions_writing.sol index e9310d91f..11d5c2615 100644 --- a/examples/scripts/functions_writing.sol +++ b/examples/scripts/functions_writing.sol @@ -2,12 +2,12 @@ contract Contract{ uint a; - function write(){ + function write() public{ a++; } // shadowing of a - function dont_write(uint a){ + function dont_write(uint a) public{ a = a +1; } diff --git a/examples/scripts/variable_in_condition.sol b/examples/scripts/variable_in_condition.sol index 4aceea687..5f664bf4b 100644 --- a/examples/scripts/variable_in_condition.sol +++ b/examples/scripts/variable_in_condition.sol @@ -2,17 +2,17 @@ contract Contract{ uint a; - function condition(){ + function condition() public{ if(a==0){ } } - function call_require(){ + function call_require() public{ require(a==0); } - function read_and_write(){ + function read_and_write() public{ a = a + 1; } From 2916af5e90bfde63216dac8cb7e6a74a6c47cb40 Mon Sep 17 00:00:00 2001 From: Josselin Date: Tue, 11 Dec 2018 16:17:39 -0500 Subject: [PATCH 6/6] Improve sha256/ripemd160 support --- slither/core/declarations/solidity_variables.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/slither/core/declarations/solidity_variables.py b/slither/core/declarations/solidity_variables.py index 1983667f8..091e627c1 100644 --- a/slither/core/declarations/solidity_variables.py +++ b/slither/core/declarations/solidity_variables.py @@ -36,8 +36,10 @@ SOLIDITY_FUNCTIONS = {"gasleft()":['uint256'], "keccak256()":['bytes32'], "keccak256(bytes)":['bytes32'], # Solidity 0.5 "sha256()":['bytes32'], + "sha256(bytes)":['bytes32'], # Solidity 0.5 "sha3()":['bytes32'], "ripemd160()":['bytes32'], + "ripemd160(bytes)":['bytes32'], # Solidity 0.5 "ecrecover(bytes32,uint8,bytes32,bytes32)":['address'], "selfdestruct(address)":[], "suicide(address)":[],