Merge branch 'dev' into bugfix/593

pull/625/head
Josselin 4 years ago
commit 4524bd958d
  1. 8
      .github/workflows/ci.yml
  2. 44
      .github/workflows/detectors.yml
  3. 4
      .github/workflows/linter.yml
  4. 44
      .github/workflows/parser.yml
  5. 2
      CONTRIBUTING.md
  6. 4
      examples/scripts/convert_to_ir.py
  7. 18
      examples/scripts/data_dependency.py
  8. 2
      examples/scripts/export_dominator_tree_to_dot.py
  9. 2
      examples/scripts/functions_called.py
  10. 4
      plugin_example/setup.py
  11. 3
      pyproject.toml
  12. 47
      scripts/ci_generate_test_detectors_4.sh
  13. 28
      scripts/ci_generate_test_detectors_5.sh
  14. 11
      scripts/ci_generate_test_detectors_6.sh
  15. 11
      scripts/ci_generate_test_detectors_7.sh
  16. 8
      scripts/ci_test_cli.sh
  17. 42
      scripts/ci_test_detectors_4.sh
  18. 51
      scripts/ci_test_detectors_5.sh
  19. 7
      scripts/ci_test_detectors_6.sh
  20. 7
      scripts/ci_test_detectors_7.sh
  21. 6
      setup.py
  22. 17
      slither/__main__.py
  23. 19
      slither/analyses/data_dependency/data_dependency.py
  24. 5
      slither/analyses/write/are_variables_written.py
  25. 12
      slither/core/cfg/node.py
  26. 37
      slither/core/declarations/contract.py
  27. 23
      slither/core/declarations/function.py
  28. 4
      slither/core/expressions/assignment_operation.py
  29. 2
      slither/core/expressions/expression_typed.py
  30. 7
      slither/core/slither_core.py
  31. 3
      slither/core/solidity_types/elementary_type.py
  32. 4
      slither/core/solidity_types/function_type.py
  33. 3
      slither/core/solidity_types/type_information.py
  34. 4
      slither/core/source_mapping/source_mapping.py
  35. 8
      slither/detectors/abstract_detector.py
  36. 3
      slither/detectors/attributes/locked_ether.py
  37. 8
      slither/detectors/functions/arbitrary_send.py
  38. 20
      slither/detectors/naming_convention/naming_convention.py
  39. 4
      slither/detectors/operations/block_timestamp.py
  40. 3
      slither/detectors/reentrancy/reentrancy.py
  41. 12
      slither/detectors/reentrancy/reentrancy_benign.py
  42. 10
      slither/detectors/reentrancy/reentrancy_eth.py
  43. 12
      slither/detectors/reentrancy/reentrancy_events.py
  44. 18
      slither/detectors/reentrancy/reentrancy_no_gas.py
  45. 7
      slither/detectors/reentrancy/reentrancy_read_before_write.py
  46. 7
      slither/formatters/attributes/constant_pragma.py
  47. 7
      slither/formatters/naming_convention/naming_convention.py
  48. 58
      slither/printers/call/call_graph.py
  49. 6
      slither/printers/functions/authorization.py
  50. 12
      slither/printers/functions/cfg.py
  51. 15
      slither/printers/guidance/echidna.py
  52. 6
      slither/printers/summary/evm.py
  53. 19
      slither/printers/summary/function.py
  54. 9
      slither/printers/summary/human_summary.py
  55. 5
      slither/printers/summary/require_calls.py
  56. 7
      slither/slither.py
  57. 30
      slither/slithir/convert.py
  58. 11
      slither/slithir/operations/binary.py
  59. 6
      slither/slithir/operations/library_call.py
  60. 9
      slither/slithir/tmp_operations/tmp_call.py
  61. 18
      slither/slithir/utils/ssa.py
  62. 9
      slither/slithir/utils/utils.py
  63. 13
      slither/solc_parsing/declarations/contract.py
  64. 20
      slither/solc_parsing/declarations/function.py
  65. 45
      slither/solc_parsing/expressions/expression_parsing.py
  66. 32
      slither/solc_parsing/slitherSolc.py
  67. 19
      slither/solc_parsing/solidity_types/type_parsing.py
  68. 2
      slither/solc_parsing/variables/variable_declaration.py
  69. 43
      slither/solc_parsing/yul/parse_yul.py
  70. 3
      slither/tools/erc_conformance/__main__.py
  71. 13
      slither/tools/flattening/__main__.py
  72. 4
      slither/tools/flattening/export/export.py
  73. 15
      slither/tools/flattening/flattening.py
  74. 11
      slither/tools/kspec_coverage/__main__.py
  75. 3
      slither/tools/possible_paths/__main__.py
  76. 3
      slither/tools/possible_paths/possible_paths.py
  77. 4
      slither/tools/properties/__main__.py
  78. 19
      slither/tools/properties/properties/erc20.py
  79. 11
      slither/tools/properties/properties/ercs/erc20/unit_tests/truffle.py
  80. 2
      slither/tools/properties/properties/properties.py
  81. 5
      slither/tools/similarity/__main__.py
  82. 15
      slither/tools/slither_format/__main__.py
  83. 5
      slither/tools/slither_format/slither_format.py
  84. 5
      slither/tools/upgradeability/__main__.py
  85. 6
      slither/tools/upgradeability/checks/abstract_checks.py
  86. 1
      slither/utils/command_line.py
  87. 26
      slither/utils/comparable_enum.py
  88. 47
      slither/utils/erc.py
  89. 12
      slither/utils/expression_manipulations.py
  90. 4
      slither/utils/inheritance_analysis.py
  91. 44
      slither/utils/output.py
  92. 11
      tests/ast-parsing/assembly-all.sol
  93. 15
      tests/ast-parsing/assignment-0.4.0.sol
  94. 17
      tests/ast-parsing/assignment-0.4.7.sol
  95. 22
      tests/ast-parsing/binaryoperation-0.4.0.sol
  96. 24
      tests/ast-parsing/binaryoperation-0.4.7.sol
  97. 21
      tests/ast-parsing/break-all.sol
  98. 9
      tests/ast-parsing/conditional-all.sol
  99. 21
      tests/ast-parsing/continue-all.sol
  100. 35
      tests/ast-parsing/contract-0.4.0.sol
  101. Some files were not shown because too many files have changed in this diff Show More

@ -20,11 +20,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
type: ["detectors_4",
"detectors_5",
"detectors_6",
"detectors_7",
"cli",
type: ["cli",
"data_dependency",
"embark",
"erc",
@ -35,7 +31,7 @@ jobs:
"simil",
"slither_config",
"truffle",
"upgradability",
"upgradability",
"prop"]
steps:
- uses: actions/checkout@v1

@ -0,0 +1,44 @@
---
name: Detectors tests
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: Detectors tests
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: |
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
- name: Test with pytest
run: |
pytest tests/test_detectors.py

@ -9,6 +9,9 @@ defaults:
on:
pull_request:
branches: [master, dev]
schedule:
# run CI every day even if no PRs/merges occur
- cron: '0 12 * * *'
jobs:
build:
@ -69,6 +72,7 @@ jobs:
VALIDATE_PYTHON: false
VALIDATE_PYTHON_PYLINT: false
VALIDATE_PYTHON_BLACK: false
VALIDATE_PYTHON_ISORT: false
# Always false
VALIDATE_JSON: false
VALIDATE_JAVASCRIPT_STANDARD: false

@ -0,0 +1,44 @@
---
name: Parser tests
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: Parser tests
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: |
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
- name: Test with pytest
run: |
pytest tests/test_ast_parsing.py

@ -23,6 +23,7 @@ Some pull request guidelines:
## Development Environment
Instructions for installing a development version of Slither can be found in our [wiki](https://github.com/crytic/slither/wiki/Developer-installation).
To run the unit tests, you need `deepdiff` installed (`pip install deepdiff`).
## Linters
Several linters and security checkers are run on the PRs.
@ -32,6 +33,7 @@ To run them locally:
- `pylint slither --rconfig pyproject.toml`
- `black slither --config pyproject.toml`
We use black `19.10b0`.
## Detectors regression tests
For each new detector, at least one regression tests must be present.

@ -12,10 +12,10 @@ slither = Slither(sys.argv[1])
# Get the contract
contract = slither.get_contract_from_name("Test")
assert contract
# Get the variable
test = contract.get_function_from_signature("one()")
assert test
nodes = test.nodes
for node in nodes:

@ -14,7 +14,7 @@ if len(sys.argv) != 2:
slither = Slither(sys.argv[1])
contract = slither.get_contract_from_name("Simple")
assert contract
destination = contract.get_state_variable_from_name("destination")
source = contract.get_state_variable_from_name("source")
@ -36,9 +36,11 @@ print("{} is tainted {}".format(destination, is_tainted(destination, contract)))
assert is_tainted(destination, contract)
contract = slither.get_contract_from_name("Reference")
assert contract
destination = contract.get_state_variable_from_name("destination")
assert destination
source = contract.get_state_variable_from_name("source")
assert source
print("Reference contract")
print(
@ -72,9 +74,11 @@ assert is_tainted(destination_indirect_2, contract)
print("SolidityVar contract")
contract = slither.get_contract_from_name("SolidityVar")
assert contract
addr_1 = contract.get_state_variable_from_name("addr_1")
assert addr_1
addr_2 = contract.get_state_variable_from_name("addr_2")
assert addr_2
msgsender = SolidityVariableComposed("msg.sender")
print(
"{} is dependent of {}: {}".format(addr_1, msgsender, is_dependent(addr_1, msgsender, contract))
@ -88,8 +92,11 @@ assert not is_dependent(addr_2, msgsender, contract)
print("Intermediate contract")
contract = slither.get_contract_from_name("Intermediate")
assert contract
destination = contract.get_state_variable_from_name("destination")
assert destination
source = contract.get_state_variable_from_name("source")
assert source
print(
"{} is dependent of {}: {}".format(
@ -119,11 +126,16 @@ assert is_dependent(destination, source, contract_derived)
print("PropagateThroughArguments contract")
contract = slither.get_contract_from_name("PropagateThroughArguments")
assert contract
var_tainted = contract.get_state_variable_from_name("var_tainted")
assert var_tainted
var_not_tainted = contract.get_state_variable_from_name("var_not_tainted")
assert var_not_tainted
var_dependant = contract.get_state_variable_from_name("var_dependant")
assert var_dependant
f = contract.get_function_from_signature("f(uint256)")
assert f
user_input = f.parameters[0]
f2 = contract.get_function_from_signature("f2(uint256,uint256)")

@ -10,7 +10,7 @@ if len(sys.argv) != 2:
slither = Slither(sys.argv[1])
for contract in slither.contracts:
for function in contract.functions + contract.modifiers:
for function in list(contract.functions) + list(contract.modifiers):
filename = "{}-{}-{}_dom.dot".format(sys.argv[1], contract.name, function.full_name)
print("Export {}".format(filename))
function.dominator_tree_to_dot(filename)

@ -10,9 +10,11 @@ slither = Slither(sys.argv[1])
# Get the contract
contract = slither.get_contract_from_name("Contract")
assert contract
# Get the variable
entry_point = contract.get_function_from_signature("entry_point()")
assert entry_point
all_calls = entry_point.all_internal_calls()

@ -9,7 +9,5 @@ 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",},
)

@ -17,5 +17,6 @@ too-many-ancestors,
logging-fstring-interpolation,
logging-not-lazy,
duplicate-code,
import-error
import-error,
unsubscriptable-object
"""

@ -1,47 +0,0 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.4.25"
# Be sure that only one of the following line is uncommented before running the script
#generate_expected_json tests/deprecated_calls.sol "deprecated-standards"
#generate_expected_json tests/erc20_indexed.sol "erc20-indexed"
#generate_expected_json tests/incorrect_erc20_interface.sol "erc20-interface"
#generate_expected_json tests/incorrect_erc721_interface.sol "erc721-interface"
#generate_expected_json tests/uninitialized.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.sol "reentrancy-eth"
#generate_expected_json tests/reentrancy.sol "reentrancy-unlimited-gas"
#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/external_function_2.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-asm"
#generate_expected_json tests/constant.sol "constant-function-state"
#generate_expected_json tests/unused_return.sol "unused-return"
#generate_expected_json tests/shadowing_state_variable.sol "shadowing-state"
#generate_expected_json tests/shadowing_abstract.sol "shadowing-abstract"
#generate_expected_json tests/timestamp.sol "timestamp"
#generate_expected_json tests/multiple_calls_in_loop.sol "calls-loop"
#generate_expected_json tests/shadowing_builtin_symbols.sol "shadowing-builtin"
#generate_expected_json tests/shadowing_local_variable.sol "shadowing-local"
#generate_expected_json tests/solc_version_incorrect.sol "solc-version"
#generate_expected_json tests/right_to_left_override.sol "rtlo"
#generate_expected_json tests/unchecked_lowlevel.sol "unchecked-lowlevel"

@ -1,28 +0,0 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.5.1"
# Be sure that only one of the following line is uncommented before running the script
# generate_expected_json tests/void-cst.sol "void-cst"
# generate_expected_json tests/solc_version_incorrect_05.ast.json "solc-version"
# 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/old_solc.sol.json "solc-version"
# generate_expected_json tests/reentrancy-0.5.1.sol "reentrancy-eth"
# generate_expected_json tests/reentrancy-0.5.1-events.sol "reentrancy-events"
# 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-asm"
# generate_expected_json tests/constant-0.5.1.sol "constant-function-state"
# generate_expected_json tests/incorrect_equality.sol "incorrect-equality"
# generate_expected_json tests/too_many_digits.sol "too-many-digits"
# generate_expected_json tests/unchecked_lowlevel-0.5.1.sol "unchecked-lowlevel"
# generate_expected_json tests/unchecked_send-0.5.1.sol "unchecked-send"

@ -1,11 +0,0 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.6.11"
# Be sure that only one of the following line is uncommented before running the script
#generate_expected_json tests/filename.sol "detector_name"

@ -1,11 +0,0 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.7.0"
# Be sure that only one of the following line is uncommented before running the script
#generate_expected_json tests/filename.sol "detector_name"

@ -2,17 +2,19 @@
### Test
if ! slither "tests/*.json" --solc-ast --ignore-return-value; then
solc use 0.7.0
if ! slither "tests/config/test.sol" --solc-ast --ignore-return-value; then
echo "--solc-ast failed"
exit 1
fi
if ! slither "tests/*0.5*.sol" --solc-disable-warnings --ignore-return-value; then
if ! slither "tests/config/test.sol" --solc-disable-warnings --ignore-return-value; then
echo "--solc-disable-warnings failed"
exit 1
fi
if ! slither "tests/*0.5*.sol" --disable-color --ignore-return-value; then
if ! slither "tests/config/test.sol" --disable-color --ignore-return-value; then
echo "--disable-color failed"
exit 1
fi

@ -1,42 +0,0 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.4.25"
test_slither tests/unchecked_lowlevel.sol "unchecked-lowlevel"
test_slither tests/deprecated_calls.sol "deprecated-standards"
test_slither tests/erc20_indexed.sol "erc20-indexed"
test_slither tests/incorrect_erc20_interface.sol "erc20-interface"
test_slither tests/incorrect_erc721_interface.sol "erc721-interface"
test_slither tests/uninitialized.sol "uninitialized-state"
test_slither tests/backdoor.sol "backdoor"
test_slither tests/backdoor.sol "suicidal"
test_slither tests/pragma.0.4.24.sol "pragma"
test_slither tests/old_solc.sol.json "solc-version"
test_slither tests/reentrancy.sol "reentrancy-eth"
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/external_function_2.sol "external-function"
test_slither tests/naming_convention.sol "naming-convention"
test_slither tests/controlled_delegatecall.sol "controlled-delegatecall"
test_slither tests/uninitialized_local_variable.sol "uninitialized-local"
test_slither tests/constant.sol "constant-function-asm"
test_slither tests/constant.sol "constant-function-state"
test_slither tests/unused_return.sol "unused-return"
test_slither tests/shadowing_abstract.sol "shadowing-abstract"
test_slither tests/shadowing_state_variable.sol "shadowing-state"
test_slither tests/timestamp.sol "timestamp"
test_slither tests/multiple_calls_in_loop.sol "calls-loop"
test_slither tests/shadowing_builtin_symbols.sol "shadowing-builtin"
test_slither tests/shadowing_local_variable.sol "shadowing-local"
test_slither tests/solc_version_incorrect.sol "solc-version"
test_slither tests/right_to_left_override.sol "rtlo"

@ -1,51 +0,0 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.5.1"
test_slither tests/void-cst.sol "void-cst"
test_slither tests/solc_version_incorrect_05.ast.json "solc-version"
test_slither tests/unchecked_lowlevel-0.5.1.sol "unchecked-lowlevel"
test_slither tests/unchecked_send-0.5.1.sol "unchecked-send"
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-eth"
test_slither tests/reentrancy-0.5.1-events.sol "reentrancy-events"
test_slither tests/tx_origin-0.5.1.sol "tx-origin"
test_slither tests/unused_state.sol "unused-state"
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/external_function_2.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-0.5.1.sol "constant-function-asm"
test_slither tests/constant-0.5.1.sol "constant-function-state"
test_slither tests/unused_return.sol "unused-return"
test_slither tests/timestamp.sol "timestamp"
test_slither tests/incorrect_equality.sol "incorrect-equality"
test_slither tests/too_many_digits.sol "too-many-digits"
### Test scripts
if ! python examples/scripts/functions_called.py examples/scripts/functions_called.sol; then
exit 1
fi
if ! python examples/scripts/functions_writing.py examples/scripts/functions_writing.sol; then
exit 1
fi
if ! python examples/scripts/variable_in_condition.py examples/scripts/variable_in_condition.sol; then
exit 1
fi
exit 0

@ -1,7 +0,0 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.6.11"
# test_slither tests/filename.sol "detector_name"

@ -1,7 +0,0 @@
#!/usr/bin/env bash
source "$(dirname "$0")""/ci_test.sh"
solc use "0.7.0"
# test_slither tests/filename.sol "detector_name"

@ -11,10 +11,10 @@ setup(
install_requires=[
"prettytable>=0.7.2",
"pysha3>=1.0.2",
"crytic-compile>=0.1.9",
# "crytic-compile",
# "crytic-compile>=0.1.9",
"crytic-compile",
],
# dependency_links=["git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile"],
dependency_links=["git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile"],
license="AGPL-3.0",
long_description=open("README.md").read(),
entry_points={

@ -402,10 +402,7 @@ def parse_args(detector_classes, printer_classes):
)
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(
@ -440,10 +437,7 @@ def parse_args(detector_classes, printer_classes):
)
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(
@ -481,6 +475,13 @@ def parse_args(detector_classes, printer_classes):
default=defaults_flag_in_config["legacy_ast"],
)
parser.add_argument(
"--skip-assembly",
help=argparse.SUPPRESS,
action="store_true",
default=defaults_flag_in_config["skip_assembly"],
)
parser.add_argument(
"--ignore-return-value",
help=argparse.SUPPRESS,

@ -135,9 +135,7 @@ 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.
@ -172,9 +170,7 @@ 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).
@ -380,16 +376,7 @@ 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

@ -35,10 +35,7 @@ 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

@ -101,7 +101,7 @@ class NodeType(Enum):
# Node not related to the CFG
# Use for state variable declaration
OTHER_ENTRYPOINT = 0x50
OTHER_ENTRYPOINT = 0x60
# @staticmethod
def __str__(self):
@ -137,6 +137,8 @@ class NodeType(Enum):
return "BEGIN_LOOP"
if self == NodeType.ENDLOOP:
return "END_LOOP"
if self == NodeType.OTHER_ENTRYPOINT:
return "OTHER_ENTRYPOINT"
return "Unknown type {}".format(hex(self.value))
@ -798,15 +800,11 @@ 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

@ -24,7 +24,7 @@ from slither.utils.tests_pattern import is_test_contract
# pylint: disable=too-many-lines,too-many-instance-attributes,import-outside-toplevel,too-many-nested-blocks
if TYPE_CHECKING:
from slither.utils.type_helpers import LibraryCallType, HighLevelCallType
from slither.utils.type_helpers import LibraryCallType, HighLevelCallType, InternalCallType
from slither.core.declarations import Enum, Event, Modifier
from slither.core.declarations import Structure
from slither.slithir.variables.variable import SlithIRVariable
@ -282,8 +282,8 @@ class Contract(ChildSlither, SourceMapping): # pylint: disable=too-many-public-
"""
List all of the slithir variables (non SSA)
"""
slithir_variables = [f.slithir_variables for f in self.functions + self.modifiers] # type: ignore
slithir_variables = [item for sublist in slithir_variables for item in sublist]
slithir_variabless = [f.slithir_variables for f in self.functions + self.modifiers] # type: ignore
slithir_variables = [item for sublist in slithir_variabless for item in sublist]
return list(set(slithir_variables))
# endregion
@ -726,20 +726,20 @@ class Contract(ChildSlither, SourceMapping): # pylint: disable=too-many-public-
###################################################################################
@property
def all_functions_called(self) -> List["Function"]:
def all_functions_called(self) -> List["InternalCallType"]:
"""
list(Function): List of functions reachable from the contract
Includes super, and private/internal functions not shadowed
"""
all_calls = [f for f in self.functions + self.modifiers if not f.is_shadowed] # type: ignore
all_callss = [f.all_internal_calls() for f in all_calls] + [all_calls]
all_functions = [f for f in self.functions + self.modifiers if not f.is_shadowed] # type: ignore
all_callss = [f.all_internal_calls() for f in all_functions] + [list(all_functions)]
all_calls = [item for sublist in all_callss for item in sublist]
all_calls = list(set(all_calls))
all_constructors = [c.constructor for c in self.inheritance if c.constructor]
all_constructors = list(set(all_constructors))
set_all_calls = set(all_calls + all_constructors)
set_all_calls = set(all_calls + list(all_constructors))
return [c for c in set_all_calls if isinstance(c, Function)]
@ -748,11 +748,11 @@ class Contract(ChildSlither, SourceMapping): # pylint: disable=too-many-public-
"""
list(StateVariable): List all of the state variables written
"""
all_state_variables_written = [
all_state_variables_writtens = [
f.all_state_variables_written() for f in self.functions + self.modifiers # type: ignore
]
all_state_variables_written = [
item for sublist in all_state_variables_written for item in sublist
item for sublist in all_state_variables_writtens for item in sublist
]
return list(set(all_state_variables_written))
@ -761,11 +761,11 @@ class Contract(ChildSlither, SourceMapping): # pylint: disable=too-many-public-
"""
list(StateVariable): List all of the state variables read
"""
all_state_variables_read = [
all_state_variables_reads = [
f.all_state_variables_read() for f in self.functions + self.modifiers # type: ignore
]
all_state_variables_read = [
item for sublist in all_state_variables_read for item in sublist
item for sublist in all_state_variables_reads for item in sublist
]
return list(set(all_state_variables_read))
@ -774,8 +774,8 @@ class Contract(ChildSlither, SourceMapping): # pylint: disable=too-many-public-
"""
list((Contract, Function): List all of the libraries func called
"""
all_high_level_calls = [f.all_library_calls() for f in self.functions + self.modifiers] # type: ignore
all_high_level_calls = [item for sublist in all_high_level_calls for item in sublist]
all_high_level_callss = [f.all_library_calls() for f in self.functions + self.modifiers] # type: ignore
all_high_level_calls = [item for sublist in all_high_level_callss for item in sublist]
return list(set(all_high_level_calls))
@property
@ -783,8 +783,8 @@ class Contract(ChildSlither, SourceMapping): # pylint: disable=too-many-public-
"""
list((Contract, Function|Variable)): List all of the external high level calls
"""
all_high_level_calls = [f.all_high_level_calls() for f in self.functions + self.modifiers] # type: ignore
all_high_level_calls = [item for sublist in all_high_level_calls for item in sublist]
all_high_level_callss = [f.all_high_level_calls() for f in self.functions + self.modifiers] # type: ignore
all_high_level_calls = [item for sublist in all_high_level_callss for item in sublist]
return list(set(all_high_level_calls))
# endregion
@ -794,9 +794,7 @@ class Contract(ChildSlither, SourceMapping): # pylint: disable=too-many-public-
###################################################################################
###################################################################################
def get_summary(
self, include_shadowed=True
) -> Tuple[str, List[str], List[str], List[str], List[str]]:
def get_summary(self, include_shadowed=True) -> Tuple[str, List[str], List[str], List, List]:
"""Return the function summary
:param include_shadowed: boolean to indicate if shadowed functions should be included (default True)
@ -1097,6 +1095,7 @@ class Contract(ChildSlither, SourceMapping): # pylint: disable=too-many-public-
v.node_initialization = next_node
prev_node.add_son(next_node)
next_node.add_father(prev_node)
prev_node = next_node
counter += 1
break
@ -1124,6 +1123,7 @@ class Contract(ChildSlither, SourceMapping): # pylint: disable=too-many-public-
v.node_initialization = next_node
prev_node.add_son(next_node)
next_node.add_father(prev_node)
prev_node = next_node
counter += 1
break
@ -1141,6 +1141,7 @@ class Contract(ChildSlither, SourceMapping): # pylint: disable=too-many-public-
node.set_offset(variable.source_mapping, self.slither)
node.set_function(func)
func.add_node(node)
assert variable.expression
expression = AssignmentOperation(
Identifier(variable),
variable.expression,

@ -53,10 +53,7 @@ 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
@ -1144,9 +1141,7 @@ class Function(
@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]
@ -1298,7 +1293,7 @@ class Function(
with open(filename, "w", encoding="utf8") as f:
f.write(content)
def slithir_cfg_to_dot_str(self) -> str:
def slithir_cfg_to_dot_str(self, skip_expressions=False) -> str:
"""
Export the CFG to a DOT format. The nodes includes the Solidity expressions and the IRs
:return: the DOT content
@ -1310,9 +1305,9 @@ class Function(
content += "digraph{\n"
for node in self.nodes:
label = "Node Type: {} {}\n".format(str(node.type), node.node_id)
if node.expression:
if node.expression and not skip_expressions:
label += "\nEXPRESSION:\n{}\n".format(node.expression)
if node.irs:
if node.irs and not skip_expressions:
label += "\nIRs:\n" + "\n".join([str(ir) for ir in node.irs])
content += '{}[label="{}"];\n'.format(node.node_id, label)
if node.type in [NodeType.IF, NodeType.IFLOOP]:
@ -1602,14 +1597,10 @@ class Function(
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

@ -91,7 +91,7 @@ class AssignmentOperation(ExpressionTyped):
super().__init__()
left_expression.set_lvalue()
self._expressions = [left_expression, right_expression]
self._type = expression_type
self._type: Optional["Type"] = expression_type
self._expression_return_type: Optional["Type"] = expression_return_type
@property
@ -111,7 +111,7 @@ class AssignmentOperation(ExpressionTyped):
return self._expressions[1]
@property
def type(self) -> AssignmentOperationType:
def type(self) -> Optional["Type"]:
return self._type
def __str__(self):

@ -12,7 +12,7 @@ class ExpressionTyped(Expression): # pylint: disable=too-few-public-methods
self._type: Optional["Type"] = None
@property
def type(self):
def type(self) -> Optional["Type"]:
return self._type
@type.setter

@ -76,6 +76,7 @@ class SlitherCore(Context): # pylint: disable=too-many-instance-attributes,too-
# If set to true, slither will not catch errors during parsing
self._disallow_partial: bool = False
self._skip_assembly: bool = False
###################################################################################
###################################################################################
@ -273,7 +274,7 @@ class SlitherCore(Context): # pylint: disable=too-many-instance-attributes,too-
- The --exclude-dependencies flag is set and results are only related to dependencies
"""
source_mapping_elements = [
elem["source_mapping"]["filename_absolute"]
elem["source_mapping"].get("filename_absolute", "unknown")
for elem in r["elements"]
if "source_mapping" in elem
]
@ -390,6 +391,10 @@ class SlitherCore(Context): # pylint: disable=too-many-instance-attributes,too-
"""
return self._disallow_partial
@property
def skip_assembly(self) -> bool:
return self._skip_assembly
# endregion
###################################################################################
###################################################################################

@ -176,7 +176,8 @@ class ElementaryType(Type):
def storage_size(self) -> Tuple[int, bool]:
if self._type == "string" or self._type == "bytes":
return 32, True
if self.size is None:
return 32, True
return int(self.size / 8), False
def __str__(self):

@ -6,9 +6,7 @@ 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)

@ -1,5 +1,6 @@
from typing import TYPE_CHECKING, Tuple
from slither.core.solidity_types import ElementaryType
from slither.core.solidity_types.type import Type
if TYPE_CHECKING:
@ -13,7 +14,7 @@ class TypeInformation(Type):
# pylint: disable=import-outside-toplevel
from slither.core.declarations.contract import Contract
assert isinstance(c, Contract)
assert isinstance(c, (Contract, ElementaryType))
super().__init__()
self._type = c

@ -150,9 +150,9 @@ class SourceMapping(Context):
def source_mapping_to_markdown(self, markdown_root: str) -> str:
lines = self._get_lines_str(line_descr="L")
return f'{markdown_root}{self.source_mapping["filename_relative"]}{lines}'
return f'{markdown_root}{self.source_mapping.get("filename_relative", "")}{lines}'
@property
def source_mapping_str(self) -> str:
lines = self._get_lines_str()
return f'{self.source_mapping["filename_short"]}{lines}'
return f'{self.source_mapping.get("filename_short", "")}{lines}'

@ -1,9 +1,11 @@
import abc
import re
from typing import Optional
from slither.utils.colors import green, yellow, red
from slither.formatters.exceptions import FormatImpossible
from slither.formatters.utils.patches import apply_patch, create_diff
from slither.utils.comparable_enum import ComparableEnum
from slither.utils.output import Output
@ -11,7 +13,7 @@ class IncorrectDetectorInitialization(Exception):
pass
class DetectorClassification: # pylint: disable=too-few-public-methods
class DetectorClassification(ComparableEnum):
HIGH = 0
MEDIUM = 1
LOW = 2
@ -39,8 +41,8 @@ classification_txt = {
class AbstractDetector(metaclass=abc.ABCMeta):
ARGUMENT = "" # run the detector with slither.py --ARGUMENT
HELP = "" # help information
IMPACT = None
CONFIDENCE = None
IMPACT: Optional[DetectorClassification] = None
CONFIDENCE: Optional[DetectorClassification] = None
WIKI = ""

@ -53,8 +53,7 @@ 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

@ -41,9 +41,7 @@ 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)):
@ -56,9 +54,7 @@ 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

@ -19,7 +19,7 @@ class NamingConvention(AbstractDetector):
IMPACT = DetectorClassification.INFORMATIONAL
CONFIDENCE = DetectorClassification.HIGH
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#conformity-to-solidity-naming-conventions"
WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#conformance-to-solidity-naming-conventions"
WIKI_TITLE = "Conformance to Solidity naming conventions"
WIKI_DESCRIPTION = """
@ -86,14 +86,10 @@ 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
@ -129,11 +125,7 @@ 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)

@ -36,9 +36,7 @@ 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)

@ -127,8 +127,7 @@ 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):

@ -63,11 +63,7 @@ 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
}
@ -130,8 +126,7 @@ 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"},
)
#
@ -143,8 +138,7 @@ 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.

@ -63,9 +63,7 @@ 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]
@ -130,8 +128,7 @@ 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.
@ -141,8 +138,7 @@ 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.

@ -61,11 +61,7 @@ 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:
@ -119,8 +115,7 @@ 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"},
)
#
@ -132,8 +127,7 @@ 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:

@ -72,19 +72,11 @@ 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:
@ -159,8 +151,7 @@ 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"},
)
#
@ -172,8 +163,7 @@ 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.

@ -58,9 +58,7 @@ 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]
@ -116,8 +114,7 @@ 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.

@ -70,10 +70,5 @@ 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,
)

@ -575,12 +575,7 @@ 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,
)

@ -33,39 +33,21 @@ 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),)
)
@ -102,12 +84,7 @@ 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
@ -117,10 +94,7 @@ 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(
@ -142,27 +116,15 @@ 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,
)

@ -52,11 +52,7 @@ 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"

@ -22,14 +22,16 @@ class CFG(AbstractPrinter):
continue
for function in contract.functions + contract.modifiers:
if filename:
filename = "{}-{}-{}.dot".format(filename, contract.name, function.full_name)
new_filename = "{}-{}-{}.dot".format(
filename, contract.name, function.full_name
)
else:
filename = "{}-{}.dot".format(contract.name, function.full_name)
info += "Export {}\n".format(filename)
new_filename = "{}-{}.dot".format(contract.name, function.full_name)
info += "Export {}\n".format(new_filename)
content = function.slithir_cfg_to_dot_str()
with open(filename, "w", encoding="utf8") as f:
with open(new_filename, "w", encoding="utf8") as f:
f.write(content)
all_files.append((filename, content))
all_files.append((new_filename, content))
self.info(info)

@ -76,8 +76,9 @@ def _is_constant(f: Function) -> bool: # pylint: disable=too-many-branches
:return:
"""
if f.view or f.pure:
if not f.contract.slither.crytic_compile.compiler_version.version.startswith("0.4"):
return True
if f.contract.slither.crytic_compile and f.contract.slither.crytic_compile.compiler_version:
if not f.contract.slither.crytic_compile.compiler_version.version.startswith("0.4"):
return True
if f.payable:
return False
if not f.is_implemented:
@ -99,8 +100,12 @@ def _is_constant(f: Function) -> bool: # pylint: disable=too-many-branches
if isinstance(ir, HighLevelCall):
if isinstance(ir.function, Variable) or ir.function.view or ir.function.pure:
# External call to constant functions are ensured to be constant only for solidity >= 0.5
if f.contract.slither.crytic_compile.compiler_version.version.startswith("0.4"):
return False
if (
f.contract.slither.crytic_compile
and f.contract.slither.crytic_compile.compiler_version
):
if f.contract.slither.crytic_compile.compiler_version.version.startswith("0.4"):
return False
else:
return False
if isinstance(ir, InternalCall):
@ -153,7 +158,7 @@ def json_serializable(cls):
@json_serializable
class ConstantValue(NamedTuple):
class ConstantValue(NamedTuple): # pylint: disable=inherit-non-class,too-few-public-methods
# Here value should be Union[str, int, bool]
# But the json lib in Echidna does not handle large integer in json
# So we convert everything to string

@ -101,8 +101,7 @@ 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")
@ -124,8 +123,7 @@ 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")

@ -65,26 +65,11 @@ 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,

@ -379,14 +379,7 @@ 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))

@ -46,10 +46,7 @@ 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)

@ -59,6 +59,7 @@ class Slither(SlitherCore): # pylint: disable=too-many-instance-attributes
self._parser: SlitherSolc # This could be another parser, like SlitherVyper, interface needs to be determined
self._disallow_partial: bool = kwargs.get("disallow_partial", False)
self._skip_assembly: bool = kwargs.get("skip_assembly", False)
# list of files provided (see --splitted option)
if isinstance(target, list):
@ -97,7 +98,11 @@ class Slither(SlitherCore): # pylint: disable=too-many-instance-attributes
triage_mode = kwargs.get("triage_mode", False)
self._triage_mode = triage_mode
self._parser.analyze_contracts()
self._parser.parse_contracts()
# skip_analyze is only used for testing
if not kwargs.get("skip_analyze", False):
self._parser.analyze_contracts()
def _init_from_raw_json(self, filename):
if not os.path.isfile(filename):

@ -206,8 +206,7 @@ def convert_arguments(arguments):
def is_temporary(ins):
return isinstance(
ins,
(Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure),
ins, (Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure),
)
@ -334,11 +333,11 @@ def propagate_type_and_convert_call(result, node):
result[idx] = ins
if isinstance(ins, Argument):
# In case of dupplicate arguments we overwrite the value
# This can happen because of addr.call.value(1).value(2)
if ins.get_type() in [ArgumentType.GAS]:
assert not ins.call_id in calls_gas
calls_gas[ins.call_id] = ins.argument
elif ins.get_type() in [ArgumentType.VALUE]:
assert not ins.call_id in calls_value
calls_value[ins.call_id] = ins.argument
else:
assert ins.get_type() == ArgumentType.CALL
@ -619,8 +618,7 @@ def propagate_types(ir, 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)
@ -827,10 +825,7 @@ 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
@ -1148,11 +1143,7 @@ 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)
@ -1385,14 +1376,7 @@ def remove_temporary(result):
ins
for ins in result
if not isinstance(
ins,
(
Argument,
TmpNewElementaryType,
TmpNewContract,
TmpNewArray,
TmpNewStructure,
),
ins, (Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure,),
)
]

@ -1,6 +1,7 @@
import logging
from enum import Enum
from slither.core.declarations import Function
from slither.core.solidity_types import ElementaryType
from slither.slithir.exceptions import SlithIRError
from slither.slithir.operations.lvalue import OperationWithLValue
@ -131,8 +132,8 @@ class BinaryType(Enum):
class Binary(OperationWithLValue):
def __init__(self, result, left_variable, right_variable, operation_type):
assert is_valid_rvalue(left_variable)
assert is_valid_rvalue(right_variable)
assert is_valid_rvalue(left_variable) or isinstance(left_variable, Function)
assert is_valid_rvalue(right_variable) or isinstance(right_variable, Function)
assert is_valid_lvalue(result)
assert isinstance(operation_type, BinaryType)
super().__init__()
@ -174,11 +175,7 @@ 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),

@ -38,9 +38,5 @@ 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,
)

@ -13,14 +13,7 @@ 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

@ -173,9 +173,7 @@ 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(
@ -508,8 +506,7 @@ 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,
@ -601,16 +598,7 @@ 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

@ -25,12 +25,5 @@ def is_valid_rvalue(v):
def is_valid_lvalue(v):
return isinstance(
v,
(
StateVariable,
LocalVariable,
TemporaryVariable,
ReferenceVariable,
TupleVariable,
),
v, (StateVariable, LocalVariable, TemporaryVariable, ReferenceVariable, TupleVariable,),
)

@ -51,8 +51,8 @@ class ContractSolc:
# use to remap inheritance id
self._remapping: Dict[str, str] = {}
self.baseContracts = []
self.baseConstructorContractsCalled = []
self.baseContracts: List[str] = []
self.baseConstructorContractsCalled: List[str] = []
self._linearized_base_contracts: List[int]
self._variables_parser: List[StateVariableSolc] = []
@ -441,15 +441,10 @@ class ContractSolc:
elem.set_contract(self._contract)
elem.set_contract_declarer(element_parser.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(
elem,
element_parser.function_not_parsed,
self,
)
elem_parser = Cls_parser(elem, element_parser.function_not_parsed, self,)
elem_parser.analyze_params()
if isinstance(elem, Modifier):
self._contract.slither.add_modifier(elem)

@ -48,10 +48,7 @@ class FunctionSolc:
# elems = [(type, name)]
def __init__(
self,
function: Function,
function_data: Dict,
contract_parser: "ContractSolc",
self, function: Function, function_data: Dict, contract_parser: "ContractSolc",
):
self._slither_parser: "SlitherSolc" = contract_parser.slither_parser
self._contract_parser = contract_parser
@ -276,7 +273,7 @@ class FunctionSolc:
self._content_was_analyzed = True
if self.is_compact_ast:
body = self._functionNotParsed["body"]
body = self._functionNotParsed.get("body", None)
if body and body[self.get_key()] == "Block":
self._function.is_implemented = True
@ -405,9 +402,9 @@ class FunctionSolc:
def _parse_for_compact_ast(self, statement: Dict, node: NodeSolc) -> NodeSolc:
body = statement["body"]
init_expression = statement["initializationExpression"]
condition = statement["condition"]
loop_expression = statement["loopExpression"]
init_expression = statement.get("initializationExpression", None)
condition = statement.get("condition", None)
loop_expression = statement.get("loopExpression", None)
node_startLoop = self._new_node(NodeType.STARTLOOP, statement["src"])
node_endLoop = self._new_node(NodeType.ENDLOOP, statement["src"])
@ -575,8 +572,7 @@ 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)
@ -606,7 +602,7 @@ class FunctionSolc:
link_underlying_nodes(node, try_node)
if self.is_compact_ast:
params = statement["parameters"]
params = statement.get("parameters", None)
else:
params = statement[self.get_children("children")]
@ -835,7 +831,7 @@ class FunctionSolc:
node = self._parse_block(statement, node)
elif name == "InlineAssembly":
# Added with solc 0.6 - the yul code is an AST
if "AST" in statement:
if "AST" in statement and not self.slither.skip_assembly:
self._function.contains_assembly = True
yul_object = self._new_yul_block(statement["src"])
entrypoint = yul_object.entrypoint

@ -84,14 +84,7 @@ def find_variable( # pylint: disable=too-many-locals,too-many-statements
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.contract import ContractSolc
from slither.solc_parsing.declarations.function import FunctionSolc
@ -124,9 +117,9 @@ def find_variable( # pylint: disable=too-many-locals,too-many-statements
if function:
# We look for variable declared with the referencedDeclaration attr
func_variables = function.variables_renamed
if referenced_declaration and referenced_declaration in func_variables:
return func_variables[referenced_declaration].underlying_variable
func_variables_renamed = function.variables_renamed
if referenced_declaration and referenced_declaration in func_variables_renamed:
return func_variables_renamed[referenced_declaration].underlying_variable
# If not found, check for name
func_variables = function.underlying_function.variables_as_dict
if var_name in func_variables:
@ -209,8 +202,8 @@ def find_variable( # pylint: disable=too-many-locals,too-many-statements
return enums[var_name]
# Could refer to any enum
all_enums = [c.enums_as_dict for c in contract.slither.contracts]
all_enums = {k: v for d in all_enums for k, v in d.items()}
all_enumss = [c.enums_as_dict for c in contract.slither.contracts]
all_enums = {k: v for d in all_enumss for k, v in d.items()}
if var_name in all_enums:
return all_enums[var_name]
@ -399,8 +392,10 @@ def _parse_elementary_type_name_expression(
if is_compact_ast:
value = expression["typeName"]
else:
assert "children" not in expression
value = expression["attributes"]["value"]
if "children" in expression:
value = expression["children"][0]["attributes"]["name"]
else:
value = expression["attributes"]["value"]
if isinstance(value, dict):
t = parse_type(value, caller_context)
else:
@ -484,8 +479,11 @@ def parse_expression(expression: Dict, caller_context: CallerContext) -> "Expres
if name == "FunctionCallOptions":
# call/gas info are handled in parse_call
called = parse_expression(expression["expression"], caller_context)
assert isinstance(called, (MemberAccess, NewContract))
if is_compact_ast:
called = parse_expression(expression["expression"], caller_context)
else:
called = parse_expression(expression["children"][0], caller_context)
assert isinstance(called, (MemberAccess, NewContract, Identifier, TupleExpression))
return called
if name == "TupleExpression":
@ -650,13 +648,12 @@ def parse_expression(expression: Dict, caller_context: CallerContext) -> "Expres
if is_compact_ast:
index_type = expression["typeDescriptions"]["typeString"]
left = expression["baseExpression"]
right = expression["indexExpression"]
right = expression.get("indexExpression", None)
else:
index_type = expression["attributes"]["type"]
children = expression["children"]
assert len(children) == 2
left = children[0]
right = children[1]
right = children[1] if len(children) > 1 else None
# IndexAccess is used to describe ElementaryTypeNameExpression
# if abi.decode is used
# For example, abi.decode(data, ...(uint[]) )
@ -696,9 +693,9 @@ def parse_expression(expression: Dict, caller_context: CallerContext) -> "Expres
member_access = MemberAccess(member_name, member_type, member_expression)
member_access.set_offset(src, caller_context.slither)
if str(member_access) in SOLIDITY_VARIABLES_COMPOSED:
idx = Identifier(SolidityVariableComposed(str(member_access)))
idx.set_offset(src, caller_context.slither)
return idx
id_idx = Identifier(SolidityVariableComposed(str(member_access)))
id_idx.set_offset(src, caller_context.slither)
return id_idx
return member_access
if name == "ElementaryTypeNameExpression":
@ -768,7 +765,7 @@ def parse_expression(expression: Dict, caller_context: CallerContext) -> "Expres
if is_compact_ast:
called = parse_expression(expression["modifierName"], caller_context)
arguments = []
if expression["arguments"]:
if expression.get("arguments", None):
arguments = [parse_expression(a, caller_context) for a in expression["arguments"]]
else:
children = expression["children"]

@ -20,11 +20,12 @@ logger.setLevel(logging.INFO)
class SlitherSolc:
# pylint: disable=no-self-use
# pylint: disable=no-self-use,too-many-instance-attributes
def __init__(self, filename: str, core: SlitherCore):
super().__init__()
core.filename = filename
self._contracts_by_id: Dict[int, ContractSolc] = {}
self._parsed = False
self._analyzed = False
self._underlying_contract_to_parser: Dict[Contract, ContractSolc] = dict()
@ -128,7 +129,6 @@ class SlitherSolc:
return
for contract_data in data_loaded[self.get_children()]:
assert contract_data[self.get_key()] in [
"ContractDefinition",
"PragmaDirective",
@ -155,7 +155,7 @@ class SlitherSolc:
if self.is_compact_ast:
import_directive = Import(contract_data["absolutePath"])
else:
import_directive = Import(contract_data["attributes"]["absolutePath"])
import_directive = Import(contract_data["attributes"].get("absolutePath", ""))
import_directive.set_offset(contract_data["src"], self._core)
self._core.import_directives.append(import_directive)
@ -233,16 +233,20 @@ class SlitherSolc:
###################################################################################
###################################################################################
@property
def parsed(self) -> bool:
return self._parsed
@property
def analyzed(self) -> bool:
return self._analyzed
def analyze_contracts(self): # pylint: disable=too-many-statements,too-many-branches
def parse_contracts(self): # pylint: disable=too-many-statements,too-many-branches
if not self._underlying_contract_to_parser:
logger.info(
f"No contract were found in {self._core.filename}, check the correct compilation"
)
if self._analyzed:
if self._parsed:
raise Exception("Contract analysis can be run only once!")
# First we save all the contracts in a dict
@ -348,12 +352,16 @@ Please rename it, this name is reserved for Slither's internals"""
# Then we analyse state variables, functions and modifiers
self._analyze_third_part(contracts_to_be_analyzed, libraries)
self._analyzed = True
self._parsed = True
def analyze_contracts(self): # pylint: disable=too-many-statements,too-many-branches
if not self._parsed:
raise SlitherException("Parse the contract before running analyses")
self._convert_to_slithir()
compute_dependency(self._core)
self._core.compute_storage_layout()
self._analyzed = True
def _analyze_all_enums(self, contracts_to_be_analyzed: List[ContractSolc]):
while contracts_to_be_analyzed:
@ -371,9 +379,7 @@ 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)
@ -398,9 +404,7 @@ 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)
@ -425,9 +429,7 @@ 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)

@ -102,11 +102,13 @@ def _find_from_type_name( # pylint: disable=too-many-locals,too-many-branches,t
if not var_type:
if name.startswith("function "):
found = re.findall(
"function \(([ ()a-zA-Z0-9\.,]*)\) returns \(([a-zA-Z0-9\.,]*)\)", name
"function \(([ ()a-zA-Z0-9\.,]*?)\)(?: returns \(([a-zA-Z0-9() \.,]*)\))?", name
)
assert len(found) == 1
params = found[0][0].split(",")
return_values = found[0][1].split(",")
params = [v for v in found[0][0].split(",") if v != ""]
return_values = (
[v for v in found[0][1].split(",") if v != ""] if len(found[0]) > 1 else []
)
params = [
_find_from_type_name(p, contract, contracts, structures, enums) for p in params
]
@ -132,8 +134,7 @@ 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]
@ -189,11 +190,7 @@ def parse_type(t: Union[Dict, UnknownType], caller_context):
if t[key] == "UserDefinedTypeName":
if is_compact_ast:
return _find_from_type_name(
t["typeDescriptions"]["typeString"],
contract,
contracts,
structures,
enums,
t["typeDescriptions"]["typeString"], contract, contracts, structures, enums,
)
# Determine if we have a type node (otherwise we use the name node, as some older solc did not have 'type').
@ -205,7 +202,7 @@ def parse_type(t: Union[Dict, UnknownType], caller_context):
if t[key] == "ArrayTypeName":
length = None
if is_compact_ast:
if t["length"]:
if t.get("length", None):
length = parse_expression(t["length"], caller_context)
array_type = parse_type(t["baseType"], contract_parser)
else:

@ -62,7 +62,7 @@ class VariableDeclarationSolc:
init = variable_data["initialValue"]
self._init_from_declaration(variable_data["declarations"][0], init)
elif nodeType == "VariableDeclaration":
self._init_from_declaration(variable_data, variable_data["value"])
self._init_from_declaration(variable_data, variable_data.get("value", None))
else:
raise ParsingError("Incorrect variable declaration type {}".format(nodeType))

@ -6,7 +6,6 @@ from slither.core.cfg.node import NodeType, Node, link_nodes
from slither.core.declarations import (
Function,
SolidityFunction,
SolidityVariable,
Contract,
)
from slither.core.expressions import (
@ -90,6 +89,21 @@ def link_underlying_nodes(node1: YulNode, node2: YulNode):
link_nodes(node1.underlying_node, node2.underlying_node)
def _name_to_yul_name(variable_name: str, yul_id: List[str]) -> str:
"""
Translate the variable name to a unique yul name
Within the same function, yul blocks can declare
different variables with the same name
We need to create unique name per variable
to prevent collision during the SSA generation
:param var:
:param yul_id:
:return:
"""
return variable_name + f"_{'_'.join(yul_id)}"
class YulScope(metaclass=abc.ABCMeta):
__slots__ = [
"_contract",
@ -136,7 +150,11 @@ class YulScope(metaclass=abc.ABCMeta):
def get_yul_local_variable_from_name(self, variable_name):
return next(
(v for v in self._yul_local_variables if v.underlying.name == variable_name),
(
v
for v in self._yul_local_variables
if v.underlying.name == _name_to_yul_name(variable_name, self.id)
),
None,
)
@ -144,10 +162,7 @@ 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
@ -163,7 +178,7 @@ class YulLocalVariable: # pylint: disable=too-few-public-methods
var.set_function(root.function)
var.set_offset(ast["src"], root.slither)
var.name = ast["name"]
var.name = _name_to_yul_name(ast["name"], root.id)
var.set_type(ElementaryType("uint256"))
var.set_location("memory")
@ -438,11 +453,7 @@ 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,
],
},
@ -517,7 +528,6 @@ def convert_yul_typed_name(root: YulScope, parent: YulNode, ast: Dict) -> YulNod
local_var = LocalVariable()
var = YulLocalVariable(local_var, root, ast)
root.add_yul_local_variable(var)
node = root.new_node(NodeType.VARIABLE, ast["src"])
@ -668,12 +678,15 @@ def parse_yul_identifier(root: YulScope, _node: YulNode, ast: Dict) -> Optional[
potential_name = name[:-5]
var = root.function.contract.get_state_variable_from_name(potential_name)
if var:
return Identifier(SolidityVariable(name))
return Identifier(var)
var = root.function.get_local_variable_from_name(potential_name)
if var and var.is_storage:
return Identifier(var)
if name.endswith("_offset"):
potential_name = name[:-7]
var = root.function.contract.get_state_variable_from_name(potential_name)
if var:
return Identifier(SolidityVariable(name))
return Identifier(var)
raise SlitherException(f"unresolved reference to identifier {name}")

@ -31,8 +31,7 @@ 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.")

@ -41,9 +41,7 @@ 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(
@ -54,10 +52,7 @@ 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(
@ -74,9 +69,7 @@ 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(

@ -24,9 +24,7 @@ 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)

@ -108,10 +108,7 @@ 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}")
@ -122,10 +119,7 @@ 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:
@ -139,10 +133,7 @@ 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(

@ -22,23 +22,18 @@ 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",

@ -21,8 +21,7 @@ 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(

@ -18,8 +18,7 @@ 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.

@ -105,9 +105,7 @@ 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

@ -50,7 +50,9 @@ ERC20_PROPERTIES = {
}
def generate_erc20(contract: Contract, type_property: str, addresses: Addresses):
def generate_erc20(
contract: Contract, type_property: str, addresses: Addresses
): # pylint: disable=too-many-locals
"""
Generate the ERC20 tests
Files generated:
@ -67,6 +69,9 @@ def generate_erc20(contract: Contract, type_property: str, addresses: Addresses)
:param type_property: One of ERC20_PROPERTIES.keys()
:return:
"""
if contract.slither.crytic_compile is None:
logging.error("Please compile with crytic-compile")
return
if contract.slither.crytic_compile.type not in [
PlatformType.TRUFFLE,
PlatformType.SOLC,
@ -80,11 +85,11 @@ def generate_erc20(contract: Contract, type_property: str, addresses: Addresses)
logger.error(red(errors))
return
properties = ERC20_PROPERTIES.get(type_property, None)
if properties is None:
erc_properties = ERC20_PROPERTIES.get(type_property, None)
if erc_properties is None:
logger.error(f"{type_property} unknown. Types available {ERC20_PROPERTIES.keys()}")
return
properties = properties.properties
properties = erc_properties.properties
# Generate the output directory
output_dir = _platform_to_output_dir(contract.slither.crytic_compile.platform)
@ -102,11 +107,7 @@ def generate_erc20(contract: Contract, type_property: str, addresses: Addresses)
# 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

@ -15,10 +15,7 @@ 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"
@ -38,11 +35,7 @@ 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"

@ -24,7 +24,7 @@ class PropertyCaller(Enum):
ANY = 5 # If the caller does not matter
class Property(NamedTuple):
class Property(NamedTuple): # pylint: disable=inherit-non-class,too-few-public-methods
name: str
content: str
type: PropertyType

@ -54,10 +54,7 @@ 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)

@ -8,7 +8,7 @@ from slither.tools.slither_format.slither_format import slither_format
logging.basicConfig()
logger = logging.getLogger("Slither").setLevel(logging.INFO)
logging.getLogger("Slither").setLevel(logging.INFO)
# Slither detectors for which slither-format currently works
available_detectors = [
@ -22,8 +22,6 @@ available_detectors = [
"constatnt-function-state",
]
detectors_to_run = []
def parse_args():
"""
@ -43,17 +41,10 @@ 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(

@ -65,10 +65,7 @@ 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}")

@ -57,10 +57,7 @@ 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(

@ -1,6 +1,8 @@
import abc
from typing import Optional
from slither.utils.colors import green, yellow, red
from slither.utils.comparable_enum import ComparableEnum
from slither.utils.output import Output
@ -8,7 +10,7 @@ class IncorrectCheckInitialization(Exception):
pass
class CheckClassification: # pylint: disable=too-few-public-methods
class CheckClassification(ComparableEnum):
HIGH = 0
MEDIUM = 1
LOW = 2
@ -33,7 +35,7 @@ classification_txt = {
class AbstractCheck(metaclass=abc.ABCMeta):
ARGUMENT = ""
HELP = ""
IMPACT = None
IMPACT: Optional[CheckClassification] = None
WIKI = ""

@ -39,6 +39,7 @@ defaults_flag_in_config = {
"filter_paths": None,
"generate_patches": False,
# debug command
"skip_assembly": False,
"legacy_ast": False,
"ignore_return_value": False,
"zip": None,

@ -0,0 +1,26 @@
from enum import Enum
# pylint: disable=comparison-with-callable
class ComparableEnum(Enum):
def __eq__(self, other):
if isinstance(other, ComparableEnum):
return self.value == other.value
return False
def __ne__(self, other):
if isinstance(other, ComparableEnum):
return self.value != other.value
return False
def __lt__(self, other):
if isinstance(other, ComparableEnum):
return self.value < other.value
return False
def __repr__(self):
return "%s" % (str(self.value))
def __hash__(self):
return hash(self.value)

@ -63,14 +63,7 @@ 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"],
@ -85,7 +78,7 @@ ERC223_signatures = erc_to_signatures(ERC223)
# Final
# https://eips.ethereum.org/EIPS/eip-165
ERC165_EVENTS = []
ERC165_EVENTS: List = []
ERC165 = [ERC("supportsInterface", ["bytes4"], "bool", True, True, [])]
ERC165_signatures = erc_to_signatures(ERC165)
@ -125,22 +118,10 @@ 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
@ -157,16 +138,9 @@ ERC721_signatures = erc_to_signatures(ERC721)
# Final
# https://eips.ethereum.org/EIPS/eip-1820
ERC1820_EVENTS = []
ERC1820_EVENTS: List = []
ERC1820 = [
ERC(
"canImplementInterfaceForAddress",
["bytes32", "address"],
"bytes32",
True,
True,
[],
)
ERC("canImplementInterfaceForAddress", ["bytes32", "address"], "bytes32", True, True, [],)
]
ERC1820_signatures = erc_to_signatures(ERC1820)
@ -207,14 +181,7 @@ 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(

@ -110,27 +110,21 @@ 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:

@ -10,9 +10,7 @@ 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.

@ -78,9 +78,7 @@ 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"))
@ -357,11 +355,7 @@ 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)
@ -377,11 +371,7 @@ 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)
@ -400,11 +390,7 @@ 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)
@ -424,11 +410,7 @@ 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)
@ -479,10 +461,7 @@ 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 = {}
@ -499,11 +478,7 @@ 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:
@ -514,10 +489,7 @@ 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,

@ -0,0 +1,11 @@
contract C {
function f() public {
assembly {
let x := 0
}
assembly "evmasm" {
let x := 0
}
}
}

@ -0,0 +1,15 @@
contract C {
function f() public {
uint assign;
assign = 10;
assign |= 10;
assign ^= 10;
assign &= 10;
assign += 10;
assign -= 10;
assign *= 10;
assign /= 10;
assign %= 10;
}
}

@ -0,0 +1,17 @@
contract C {
function f() public {
uint assign;
assign = 10;
assign |= 10;
assign ^= 10;
assign &= 10;
assign <<= 10;
assign >>= 10;
assign += 10;
assign -= 10;
assign *= 10;
assign /= 10;
assign %= 10;
}
}

@ -0,0 +1,22 @@
contract C {
function f() public {
1**2;
1*2;
1/2;
1&2;
1+2;
1-2;
1 & 2;
1 ^ 2;
1 | 2;
1 < 2;
1 > 2;
1 <= 2;
1 >= 2;
1 == 2;
1 != 2;
true && false;
true || false;
}
}

@ -0,0 +1,24 @@
contract C {
function f() public {
1**2;
1*2;
1/2;
1&2;
1+2;
1-2;
1 << 2;
1 >> 2;
1 & 2;
1 ^ 2;
1 | 2;
1 < 2;
1 > 2;
1 <= 2;
1 >= 2;
1 == 2;
1 != 2;
true && false;
true || false;
}
}

@ -0,0 +1,21 @@
contract C {
function f() public {
uint c;
for (uint i = 0; i < 10; i++) {
if (i % 2 == 0) {
break;
}
c++;
}
for (uint j = 0; j < 10; j++) {
for (uint k = 0; k < 10; k++) {
if (j % 2 == 0 && k % 3 == 0) {
break;
}
c++;
}
}
}
}

@ -0,0 +1,9 @@
contract C {
function f() public {
false ? 1 : 2;
5 == 6 ? 1 : 2;
1 + 2 == 3 ? 4 + 5 == 6 ? int8(0) : -1 : -2;
true ? "a" : "b";
false ? (1, 2) : (3, 4);
}
}

@ -0,0 +1,21 @@
contract C {
function f() public {
uint c;
for (uint i = 0; i < 10; i++) {
if (i % 2 == 0) {
continue;
}
c++;
}
for (uint j = 0; j < 10; j++) {
for (uint k = 0; k < 10; k++) {
if (j % 2 == 0 && k % 3 == 0) {
continue;
}
c++;
}
}
}
}

@ -0,0 +1,35 @@
// a simple contract
contract A {
}
// inheritance, no constructor
contract B is A {
function B(uint a) {
}
}
// inheritance, init in inheritance
contract C is B(4) {
}
// inheritance, init in constructor
contract D is B {
function D() B(2) {
}
}
// abstract contract
contract E is B {
}
// diamond inheritance
contract F is A {}
contract G is A {}
contract H is F, G {
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save