diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 84414e6b1..a2e289af1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,21 +6,20 @@ # pre-commit autoupdate repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: check-toml - id: check-yaml - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.1 + rev: v0.9.1 hooks: + # lint & attempt to correct failures - id: ruff args: [--fix, --show-fixes] -- repo: https://github.com/psf/black - rev: 24.8.0 - hooks: - - id: black + # compatible replacement for black + - id: ruff-format - repo: https://github.com/scop/pre-commit-shfmt - rev: v3.8.0-1 + rev: v3.10.0-2 hooks: - id: shfmt args: [--write, --indent, '4'] @@ -38,7 +37,7 @@ repos: - id: pretty-format-toml args: [--autofix] - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.29.1 + rev: 0.31.0 hooks: - id: check-circle-ci - id: check-github-workflows diff --git a/myth b/myth index 86517b841..8658fb78e 100755 --- a/myth +++ b/myth @@ -1,8 +1,9 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """mythril.py: Bug hunting on the Ethereum blockchain - http://www.github.com/ConsenSys/mythril - """ +http://www.github.com/ConsenSys/mythril +""" + from sys import exit import mythril.interfaces.cli diff --git a/mythril/analysis/module/base.py b/mythril/analysis/module/base.py index 5697aff1d..d32c21f79 100644 --- a/mythril/analysis/module/base.py +++ b/mythril/analysis/module/base.py @@ -1,4 +1,4 @@ -""" Mythril Detection Modules +"""Mythril Detection Modules This module includes an definition of the DetectionModule interface. DetectionModules implement different analysis rules to find weaknesses and vulnerabilities. diff --git a/mythril/analysis/module/loader.py b/mythril/analysis/module/loader.py index 038dbb366..9243e45e9 100644 --- a/mythril/analysis/module/loader.py +++ b/mythril/analysis/module/loader.py @@ -63,7 +63,6 @@ def get_detection_modules( result = self._modules[:] if white_list: - # Sanity check available_names = [type(module).__name__ for module in result] diff --git a/mythril/analysis/module/modules/dependence_on_origin.py b/mythril/analysis/module/modules/dependence_on_origin.py index 59253efb4..e80624fe8 100644 --- a/mythril/analysis/module/modules/dependence_on_origin.py +++ b/mythril/analysis/module/modules/dependence_on_origin.py @@ -56,7 +56,6 @@ def _analyze_state(self, state: GlobalState) -> List[Issue]: # We're in JUMPI prehook for annotation in state.mstate.stack[-2].annotations: - if isinstance(annotation, TxOriginAnnotation): constraints = copy(state.world_state.constraints) @@ -103,7 +102,6 @@ def _analyze_state(self, state: GlobalState) -> List[Issue]: issues.append(issue) else: - # In ORIGIN posthook state.mstate.stack[-1].annotate(TxOriginAnnotation()) diff --git a/mythril/analysis/module/modules/dependence_on_predictable_vars.py b/mythril/analysis/module/modules/dependence_on_predictable_vars.py index 32a5af4a8..316051f0e 100644 --- a/mythril/analysis/module/modules/dependence_on_predictable_vars.py +++ b/mythril/analysis/module/modules/dependence_on_predictable_vars.py @@ -66,17 +66,13 @@ def _analyze_state(self, state: GlobalState) -> List[Issue]: issues = [] if is_prehook(): - opcode = state.get_current_instruction()["opcode"] if opcode == "JUMPI": - # Look for predictable state variables in jump condition for annotation in state.mstate.stack[-2].annotations: - if isinstance(annotation, PredictableValueAnnotation): - constraints = state.world_state.constraints try: transaction_sequence = solver.get_transaction_sequence( @@ -137,7 +133,6 @@ def _analyze_state(self, state: GlobalState) -> List[Issue]: issues.append(issue) elif opcode == "BLOCKHASH": - param = state.mstate.stack[-1] constraint = [ @@ -151,7 +146,6 @@ def _analyze_state(self, state: GlobalState) -> List[Issue]: # Why the second constraint? Because without it Z3 returns a solution where param overflows. try: - solver.get_model( state.world_state.constraints + constraint # type: ignore ) diff --git a/mythril/analysis/module/modules/integer.py b/mythril/analysis/module/modules/integer.py index c40f27dd8..31172200c 100644 --- a/mythril/analysis/module/modules/integer.py +++ b/mythril/analysis/module/modules/integer.py @@ -200,7 +200,6 @@ def _get_title(_type): @staticmethod def _handle_sstore(state: GlobalState) -> None: - stack = state.mstate.stack value = stack[-2] @@ -214,7 +213,6 @@ def _handle_sstore(state: GlobalState) -> None: @staticmethod def _handle_jumpi(state): - stack = state.mstate.stack value = stack[-2] @@ -226,7 +224,6 @@ def _handle_jumpi(state): @staticmethod def _handle_call(state): - stack = state.mstate.stack value = stack[-3] @@ -250,7 +247,6 @@ def _handle_return(state: GlobalState) -> None: state_annotation = _get_overflowunderflow_state_annotation(state) for element in state.mstate.memory[offset : offset + length]: - if not isinstance(element, Expression): continue @@ -259,11 +255,9 @@ def _handle_return(state: GlobalState) -> None: state_annotation.overflowing_state_annotations.add(annotation) def _handle_transaction_end(self, state: GlobalState) -> List[Issue]: - state_annotation = _get_overflowunderflow_state_annotation(state) issues = [] for annotation in state_annotation.overflowing_state_annotations: - ostate = annotation.overflowing_state if ostate in self._ostates_unsatisfiable: @@ -289,7 +283,6 @@ def _handle_transaction_end(self, state: GlobalState) -> List[Issue]: ) try: - constraints = state.world_state.constraints + [annotation.constraint] transaction_sequence = solver.get_transaction_sequence( state, constraints diff --git a/mythril/analysis/module/modules/multiple_sends.py b/mythril/analysis/module/modules/multiple_sends.py index f391c7cd4..72d1ee1bc 100644 --- a/mythril/analysis/module/modules/multiple_sends.py +++ b/mythril/analysis/module/modules/multiple_sends.py @@ -63,7 +63,6 @@ def _analyze_state(self, state: GlobalState): call_offsets.append(state.get_current_instruction()["address"]) else: # RETURN or STOP - for offset in call_offsets[1:]: try: transaction_sequence = get_transaction_sequence( diff --git a/mythril/analysis/module/modules/state_change_external_calls.py b/mythril/analysis/module/modules/state_change_external_calls.py index 10f30c91b..f4035f86f 100644 --- a/mythril/analysis/module/modules/state_change_external_calls.py +++ b/mythril/analysis/module/modules/state_change_external_calls.py @@ -42,7 +42,6 @@ def __copy__(self): def get_issue( self, global_state: GlobalState, detector: DetectionModule ) -> Optional[PotentialIssue]: - if not self.state_change_states: return None constraints = Constraints() @@ -146,7 +145,6 @@ def _add_external_call(global_state: GlobalState) -> None: pass def _analyze_state(self, global_state: GlobalState) -> List[PotentialIssue]: - if global_state.environment.active_function_name == "constructor": return [] diff --git a/mythril/analysis/module/util.py b/mythril/analysis/module/util.py index 13dd88dcb..935a7204f 100644 --- a/mythril/analysis/module/util.py +++ b/mythril/analysis/module/util.py @@ -21,7 +21,6 @@ def get_detection_module_hooks( """ hook_dict: Mapping[str, List[Callable]] = defaultdict(list) for module in modules: - hooks = module.pre_hooks if hook_type == "pre" else module.post_hooks for op_code in map(lambda x: x.upper(), hooks): diff --git a/mythril/analysis/report.py b/mythril/analysis/report.py index e3b658719..ac8e856fb 100644 --- a/mythril/analysis/report.py +++ b/mythril/analysis/report.py @@ -344,7 +344,6 @@ def as_swc_standard_format(self): _issues = [] for _, issue in self.issues.items(): - idx = self.source.get_source_index(issue.bytecode_hash) try: title = SWC_TO_TITLE[issue.swc_id] diff --git a/mythril/analysis/symbolic.py b/mythril/analysis/symbolic.py index 29f639c27..c262b6262 100644 --- a/mythril/analysis/symbolic.py +++ b/mythril/analysis/symbolic.py @@ -252,17 +252,14 @@ def __init__( self.calls: List[Call] = [] for key in self.nodes: - state_index = 0 for state in self.nodes[key].states: - instruction = state.get_current_instruction() op = instruction["opcode"] if op in ("CALL", "CALLCODE", "DELEGATECALL", "STATICCALL"): - stack = state.mstate.stack if op in ("CALL", "CALLCODE"): diff --git a/mythril/analysis/traceexplore.py b/mythril/analysis/traceexplore.py index ad42fe153..d97659c2f 100644 --- a/mythril/analysis/traceexplore.py +++ b/mythril/analysis/traceexplore.py @@ -68,7 +68,6 @@ def get_serializable_statespace(statespace): i += 1 for node_key in statespace.nodes: - node = statespace.nodes[node_key] code = node.get_cfg_dict()["code"] @@ -139,11 +138,9 @@ def get_state_accounts(node_state): nodes.append(s_node) for edge in statespace.edges: - if edge.condition is None: label = "" else: - try: label = str(simplify(edge.condition)).replace("\n", "") except Z3Exception: diff --git a/mythril/ethereum/evmcontract.py b/mythril/ethereum/evmcontract.py index 85fede8e9..3477a9e29 100644 --- a/mythril/ethereum/evmcontract.py +++ b/mythril/ethereum/evmcontract.py @@ -90,7 +90,6 @@ def matches_expression(self, expression): tokens = re.split(r"\s+(and|or|not)\s+", expression, re.IGNORECASE) for token in tokens: - if token in ("and", "or", "not"): str_eval += " " + token + " " continue @@ -108,7 +107,6 @@ def matches_expression(self, expression): m = re.match(r"^func#([a-zA-Z0-9\s_,(\\)\[\]]+)#$", token) if m: - sign_hash = "0x" + sha3(m.group(1))[:4].hex() str_eval += '"' + sign_hash + '" in self.disassembly.func_hashes' diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py index fe8912690..303a9b198 100644 --- a/mythril/interfaces/cli.py +++ b/mythril/interfaces/cli.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """mythril.py: Bug hunting on the Ethereum blockchain - http://www.github.com/ConsenSys/mythril +http://www.github.com/ConsenSys/mythril """ import argparse @@ -840,7 +840,6 @@ def execute_command( exit_with_error(args.outform, "Error saving graph: " + str(e)) elif args.statespace_json: - if not analyzer.contracts: exit_with_error( args.outform, "input files do not contain any valid contracts" diff --git a/mythril/laser/ethereum/call.py b/mythril/laser/ethereum/call.py index 26d1f5f38..4286b04c8 100644 --- a/mythril/laser/ethereum/call.py +++ b/mythril/laser/ethereum/call.py @@ -202,7 +202,6 @@ def native_call( memory_out_offset: Union[int, Expression], memory_out_size: Union[int, Expression], ) -> Optional[List[GlobalState]]: - if isinstance(callee_address, BitVec) or not ( 0 < int(callee_address, 16) <= PRECOMPILE_COUNT ): diff --git a/mythril/laser/ethereum/cheat_code.py b/mythril/laser/ethereum/cheat_code.py index e6a5faca9..9bfb20b1b 100644 --- a/mythril/laser/ethereum/cheat_code.py +++ b/mythril/laser/ethereum/cheat_code.py @@ -39,6 +39,5 @@ def handle_cheat_codes( memory_out_offset: Union[int, Expression], memory_out_size: Union[int, Expression], ): - insert_ret_val(global_state) pass diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py index 50c90d6f2..cd0d721de 100644 --- a/mythril/laser/ethereum/instructions.py +++ b/mythril/laser/ethereum/instructions.py @@ -1237,8 +1237,7 @@ def _code_copy_helper( global_state.mstate.memory[concrete_memory_offset + i] = int( code[ - 2 - * (concrete_code_offset + i) : 2 + 2 * (concrete_code_offset + i) : 2 * (concrete_code_offset + i + 1) ], 16, diff --git a/mythril/laser/ethereum/strategy/extensions/bounded_loops.py b/mythril/laser/ethereum/strategy/extensions/bounded_loops.py index 55c08af2e..d81418f9b 100644 --- a/mythril/laser/ethereum/strategy/extensions/bounded_loops.py +++ b/mythril/laser/ethereum/strategy/extensions/bounded_loops.py @@ -108,7 +108,6 @@ def get_strategic_global_state(self) -> GlobalState: """ while True: - state = self.super_strategy.get_strategic_global_state() annotations = cast( diff --git a/mythril/laser/ethereum/svm.py b/mythril/laser/ethereum/svm.py index 766d4bb72..e5d2f582c 100644 --- a/mythril/laser/ethereum/svm.py +++ b/mythril/laser/ethereum/svm.py @@ -334,7 +334,6 @@ def exec(self, create=False, track_gas=False) -> Optional[List[GlobalState]]: hook() for global_state in self.strategy: - if create and self._check_create_termination(): log.debug("Hit create timeout, returning.") return final_states + [global_state] if track_gas else None @@ -499,7 +498,6 @@ def execute_state( new_global_states = [] else: - # First execute the post hook for the transaction ending instruction self._execute_post_hook(op_code, [end_signal.global_state]) diff --git a/mythril/laser/plugin/__init__.py b/mythril/laser/plugin/__init__.py index 40bd25fbe..1706ab625 100644 --- a/mythril/laser/plugin/__init__.py +++ b/mythril/laser/plugin/__init__.py @@ -1,4 +1,4 @@ -""" Laser plugins +"""Laser plugins This module contains everything to do with laser plugins diff --git a/mythril/laser/plugin/plugins/__init__.py b/mythril/laser/plugin/plugins/__init__.py index 463d66c5d..22d786c4d 100644 --- a/mythril/laser/plugin/plugins/__init__.py +++ b/mythril/laser/plugin/plugins/__init__.py @@ -1,4 +1,4 @@ -""" Plugin implementations +"""Plugin implementations This module contains the implementation of some features diff --git a/mythril/laser/plugin/plugins/dependency_pruner.py b/mythril/laser/plugin/plugins/dependency_pruner.py index 3da102256..53e9bb3d7 100644 --- a/mythril/laser/plugin/plugins/dependency_pruner.py +++ b/mythril/laser/plugin/plugins/dependency_pruner.py @@ -30,7 +30,6 @@ def get_dependency_annotation(state: GlobalState) -> DependencyAnnotation: ) if len(annotations) == 0: - """FIXME: Hack for carrying over state annotations from the STOP and RETURN states of the previous states. The states are pushed on a stack in the world state annotation and popped off the stack in the subsequent iteration. This might break if any @@ -173,7 +172,6 @@ def wanna_execute(self, address: int, annotation: DependencyAnnotation) -> bool: for location in storage_write_cache: for dependency in dependencies: - # Is there a known read operation along this path that matches a write in the previous transaction? try: @@ -319,7 +317,6 @@ def _check_basic_block(address: int, annotation: DependencyAnnotation): @symbolic_vm.laser_hook("add_world_state") def world_state_filter_hook(state: GlobalState): - if isinstance(state.current_transaction, ContractCreationTransaction): # Reset iteration variable self.iteration = 0 diff --git a/mythril/laser/plugin/plugins/mutation_pruner.py b/mythril/laser/plugin/plugins/mutation_pruner.py index c9343620e..7ea0f9a7a 100644 --- a/mythril/laser/plugin/plugins/mutation_pruner.py +++ b/mythril/laser/plugin/plugins/mutation_pruner.py @@ -60,7 +60,6 @@ def staticcall_mutator_hook(global_state: GlobalState): @symbolic_vm.laser_hook("add_world_state") def world_state_filter_hook(global_state: GlobalState): - if isinstance( global_state.current_transaction, ContractCreationTransaction ): @@ -74,7 +73,6 @@ def world_state_filter_hook(global_state: GlobalState): callvalue = global_state.environment.callvalue try: - constraints = global_state.world_state.constraints + [ UGT(callvalue, symbol_factory.BitVecVal(0, 256)) ] diff --git a/mythril/laser/plugin/plugins/summary/annotations.py b/mythril/laser/plugin/plugins/summary/annotations.py index 1359254ff..d095af529 100644 --- a/mythril/laser/plugin/plugins/summary/annotations.py +++ b/mythril/laser/plugin/plugins/summary/annotations.py @@ -32,7 +32,6 @@ def __init__( self.code = code def __copy__(self): - annotation = SummaryTrackingAnnotation( entry=self.entry, storage_pairs=deepcopy(self.storage_pairs), diff --git a/mythril/laser/plugin/plugins/summary/summary.py b/mythril/laser/plugin/plugins/summary/summary.py index 696512f34..edea3762c 100644 --- a/mythril/laser/plugin/plugins/summary/summary.py +++ b/mythril/laser/plugin/plugins/summary/summary.py @@ -87,7 +87,6 @@ def as_dict(self): ) def apply_summary(self, global_state: GlobalState): - # Copy and apply summary global_state = deepcopy(global_state) conditions = deepcopy(self.condition) @@ -126,7 +125,6 @@ def apply_summary(self, global_state: GlobalState): def substitute_exprs(expression, account_id, account, global_state): - a = Array("2_calldata", 256, 8) b = Array(f"{global_state.current_transaction.id}_calldata", 256, 8) expression.substitute(a, b) diff --git a/mythril/mythril/mythril_disassembler.py b/mythril/mythril/mythril_disassembler.py index c336b81c0..430cbe6b2 100644 --- a/mythril/mythril/mythril_disassembler.py +++ b/mythril/mythril/mythril_disassembler.py @@ -169,7 +169,6 @@ def load_from_foundry(self): cwd=project_root, executable=shutil.which(cmd[0]), ) as p: - stdout, stderr = p.communicate() stdout, stderr = (stdout.decode(), stderr.decode()) if stderr: @@ -217,7 +216,6 @@ def load_from_foundry(self): return address, contracts def check_run_integer_module(self, source_file): - with open(source_file, "r") as f: for line in f: if "unchecked" in line: diff --git a/mythril/solidity/features.py b/mythril/solidity/features.py index 59b711b09..769d39c8c 100644 --- a/mythril/solidity/features.py +++ b/mythril/solidity/features.py @@ -151,7 +151,6 @@ def traverse(node): return variables def find_variables_in_require(self, node): - nodes = self.extract_nodes(node, "require") variables = set() for parent, _ in nodes: diff --git a/mythril/solidity/soliditycontract.py b/mythril/solidity/soliditycontract.py index c8366c33e..e76fb9493 100644 --- a/mythril/solidity/soliditycontract.py +++ b/mythril/solidity/soliditycontract.py @@ -157,7 +157,6 @@ def get_contracts_from_foundry(input_file, foundry_json): "deployedBytecode" ]["object"] ): - yield SolidityContract( input_file=input_file, name=contract_name, @@ -178,7 +177,6 @@ def __init__( solc_binary="solc", solc_data=None, ): - if solc_data is None: data = get_solc_json( input_file, diff --git a/setup.py b/setup.py index dcdc16d63..765eae9e9 100755 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ 1) #> python setup.py sdist bdist_wheel 2) #> twine upload dist/* #; #optional --repository or --repository-url """ + import io import os import sys diff --git a/tests/concolic/concolic_tests.py b/tests/concolic/concolic_tests.py index 3234a2c50..9b749a8c9 100644 --- a/tests/concolic/concolic_tests.py +++ b/tests/concolic/concolic_tests.py @@ -70,7 +70,6 @@ def validate_multiple_example(output, branches): def validate_two_contract(output, branches): for branch_output, branch in zip(output, branches): if branch == "311": - # Validation for initialState # Validation for tx steps assert ( diff --git a/tests/instructions/extcodehash_test.py b/tests/instructions/extcodehash_test.py index 19d370630..ff5ad4f09 100644 --- a/tests/instructions/extcodehash_test.py +++ b/tests/instructions/extcodehash_test.py @@ -23,7 +23,6 @@ def test_extcodehash_no_account(): - # If account does not exist, return 0 og_state.mstate.stack = [symbol_factory.BitVecVal(1, 256)] new_state = instruction.evaluate(og_state)[0] @@ -31,7 +30,6 @@ def test_extcodehash_no_account(): def test_extcodehash_no_code(): - # If account code does not exist, return hash of empty set. og_state.mstate.stack = [symbol_factory.BitVecVal(1000, 256)] new_state = instruction.evaluate(og_state)[0] diff --git a/tests/laser/evm_testsuite/evm_test.py b/tests/laser/evm_testsuite/evm_test.py index a2bc52564..343d3fb4b 100644 --- a/tests/laser/evm_testsuite/evm_test.py +++ b/tests/laser/evm_testsuite/evm_test.py @@ -68,7 +68,6 @@ def load_test_data(designations): return_data = [] for designation in designations: for file_reference in (evm_test_dir / designation).iterdir(): - with file_reference.open() as file: top_level = json.load(file) @@ -113,7 +112,6 @@ def test_vmtest( gas_used: int, post_condition: dict, ) -> None: - # Arrange if test_name in ignored_test_names: return diff --git a/tests/laser/state/mstack_test.py b/tests/laser/state/mstack_test.py index 55ec63623..0356b94f6 100644 --- a/tests/laser/state/mstack_test.py +++ b/tests/laser/state/mstack_test.py @@ -24,7 +24,6 @@ def test_mstack_append_single_element(): @staticmethod def test_mstack_append_multiple_elements(): - mstack = MachineStack() for i in range(mstack.STACK_LIMIT):