Fix type hinting to mythril module and fix typehints in svm, disassembler, state modules

pull/894/head
Nikhil Parasaram 6 years ago
parent 5ae1052bdf
commit a25d782b90
  1. 5
      mythril/analysis/modules/base.py
  2. 2
      mythril/disassembler/asm.py
  3. 11
      mythril/disassembler/disassembly.py
  4. 11
      mythril/laser/ethereum/cfg.py
  5. 11
      mythril/laser/ethereum/natives.py
  6. 4
      mythril/laser/ethereum/state/machine_state.py
  7. 35
      mythril/laser/ethereum/svm.py
  8. 18
      mythril/laser/ethereum/util.py
  9. 6
      mythril/support/signatures.py
  10. 2
      tox.ini

@ -3,6 +3,7 @@ modules."""
import logging
from typing import List
from mythril.analysis.report import Issue
log = logging.getLogger(__name__)
@ -21,7 +22,7 @@ class DetectionModule:
entrypoint: str = "post",
pre_hooks: List[str] = None,
post_hooks: List[str] = None,
):
) -> None:
self.name = name
self.swc_id = swc_id
self.pre_hooks = pre_hooks if pre_hooks else []
@ -33,7 +34,7 @@ class DetectionModule:
self.name,
)
self.entrypoint = entrypoint
self._issues = []
self._issues = [] # type: List[Issue]
@property
def issues(self):

@ -90,7 +90,7 @@ def is_sequence_match(pattern: list, instruction_list: list, index: int) -> bool
return True
def disassemble(bytecode: str) -> list:
def disassemble(bytecode: bytes) -> list:
"""Disassembles evm bytecode and returns a list of instructions.
:param bytecode:

@ -3,6 +3,8 @@ from mythril.ethereum import util
from mythril.disassembler import asm
from mythril.support.signatures import SignatureDB
from typing import Dict, List
class Disassembly(object):
"""Disassembly class.
@ -14,7 +16,7 @@ class Disassembly(object):
- function entry point to function name mapping
"""
def __init__(self, code: str, enable_online_lookup: bool = False):
def __init__(self, code: str, enable_online_lookup: bool = False) -> None:
"""
:param code:
@ -23,9 +25,9 @@ class Disassembly(object):
self.bytecode = code
self.instruction_list = asm.disassemble(util.safe_decode(code))
self.func_hashes = []
self.function_name_to_address = {}
self.address_to_function_name = {}
self.func_hashes = [] # type: List[str]
self.function_name_to_address = {} # type: Dict[str, int]
self.address_to_function_name = {} # type: Dict[int, str]
# open from default locations
# control if you want to have online signature hash lookups
@ -41,7 +43,6 @@ class Disassembly(object):
index, self.instruction_list, signatures
)
self.func_hashes.append(function_hash)
if jump_target is not None and function_name is not None:
self.function_name_to_address[function_name] = jump_target
self.address_to_function_name[jump_target] = function_name

@ -1,9 +1,12 @@
"""This module."""
from enum import Enum
from typing import Dict
from typing import Dict, List, TYPE_CHECKING
from flags import Flags
if TYPE_CHECKING:
from mythril.laser.ethereum.state.global_state import GlobalState
gbl_next_uid = 0 # node counter
@ -33,7 +36,7 @@ class Node:
start_addr=0,
constraints=None,
function_name="unknown",
):
) -> None:
"""
:param contract_name:
@ -43,7 +46,7 @@ class Node:
constraints = constraints if constraints else []
self.contract_name = contract_name
self.start_addr = start_addr
self.states = []
self.states = [] # type: List[GlobalState]
self.constraints = constraints
self.function_name = function_name
self.flags = NodeFlags()
@ -86,7 +89,7 @@ class Edge:
node_to: int,
edge_type=JumpType.UNCONDITIONAL,
condition=None,
):
) -> None:
"""
:param node_from:

@ -9,7 +9,8 @@ from py_ecc.secp256k1 import N as secp256k1n
from rlp.utils import ALL_BYTES
from mythril.laser.ethereum.state.calldata import BaseCalldata, ConcreteCalldata
from mythril.laser.ethereum.util import bytearray_to_int, sha3
from mythril.laser.ethereum.util import bytearray_to_int
from ethereum.utils import sha3
from mythril.laser.smt import Concat, simplify
log = logging.getLogger(__name__)
@ -50,7 +51,7 @@ def extract32(data: bytearray, i: int) -> int:
return bytearray_to_int(o)
def ecrecover(data: Union[bytes, str, List[int]]) -> bytes:
def ecrecover(data: List[int]) -> List[int]:
"""
:param data:
@ -77,7 +78,7 @@ def ecrecover(data: Union[bytes, str, List[int]]) -> bytes:
return o
def sha256(data: Union[bytes, str, List[int]]) -> bytes:
def sha256(data: List[int]) -> List[int]:
"""
:param data:
@ -90,7 +91,7 @@ def sha256(data: Union[bytes, str, List[int]]) -> bytes:
return hashlib.sha256(data).digest()
def ripemd160(data: Union[bytes, str, List[int]]) -> bytes:
def ripemd160(data: List[int]) -> bytes:
"""
:param data:
@ -105,7 +106,7 @@ def ripemd160(data: Union[bytes, str, List[int]]) -> bytes:
return bytes(padded)
def identity(data: Union[bytes, str, List[int]]) -> bytes:
def identity(data: List[int]) -> List[int]:
"""
:param data:

@ -20,7 +20,7 @@ class MachineStack(list):
STACK_LIMIT = 1024
def __init__(self, default_list=None):
def __init__(self, default_list=None) -> None:
"""
:param default_list:
@ -95,7 +95,7 @@ class MachineState:
depth=0,
max_gas_used=0,
min_gas_used=0,
):
) -> None:
"""Constructor for machineState.
:param gas_limit:

@ -4,7 +4,7 @@ from collections import defaultdict
from copy import copy
from datetime import datetime, timedelta
from functools import reduce
from typing import Callable, Dict, List, Tuple, Union
from typing import Callable, Dict, DefaultDict, List, Tuple, Union
from mythril import alarm
from mythril.exceptions import OutOfTimeError
@ -56,7 +56,7 @@ class LaserEVM:
transaction_count=2,
requires_statespace=True,
enable_iprof=False,
):
) -> None:
"""
:param accounts:
@ -73,12 +73,12 @@ class LaserEVM:
self.world_state = world_state
self.open_states = [world_state]
self.coverage = {}
self.coverage = {} # type: Dict[str, Tuple[int, List[bool]]]
self.total_states = 0
self.dynamic_loader = dynamic_loader
self.work_list = []
self.work_list = [] # type: List[GlobalState]
self.strategy = strategy(self.work_list, max_depth)
self.max_depth = max_depth
self.transaction_count = transaction_count
@ -88,13 +88,13 @@ class LaserEVM:
self.requires_statespace = requires_statespace
if self.requires_statespace:
self.nodes = {}
self.edges = []
self.nodes = {} # type: Dict[int, Node]
self.edges = [] # type: List[Edge]
self.time = None
self.time = None # type: datetime
self.pre_hooks = defaultdict(list)
self.post_hooks = defaultdict(list)
self.pre_hooks = defaultdict(list) # type: DefaultDict[str, List[Callable]]
self.post_hooks = defaultdict(list) # type: DefaultDict[str, List[Callable]]
self.iprof = InstructionProfiler() if enable_iprof else None
@ -177,11 +177,8 @@ class LaserEVM:
self.total_states,
)
for code, coverage in self.coverage.items():
cov = (
reduce(lambda sum_, val: sum_ + 1 if val else sum_, coverage[1])
/ float(coverage[0])
* 100
)
cov = sum(coverage[1]) / float(coverage[0]) * 100
log.info("Achieved {:.2f}% coverage for code: {}".format(cov, code))
if self.iprof is not None:
@ -222,9 +219,7 @@ class LaserEVM:
"""
total_covered_instructions = 0
for _, cv in self.coverage.items():
total_covered_instructions += reduce(
lambda sum_, val: sum_ + 1 if val else sum_, cv[1]
)
total_covered_instructions += sum(cv[1])
return total_covered_instructions
def exec(self, create=False, track_gas=False) -> Union[List[GlobalState], None]:
@ -234,7 +229,7 @@ class LaserEVM:
:param track_gas:
:return:
"""
final_states = []
final_states = [] # type: List[GlobalState]
for global_state in self.strategy:
if (
self.create_timeout
@ -389,10 +384,10 @@ class LaserEVM:
instruction_index = global_state.mstate.pc
if code not in self.coverage.keys():
self.coverage[code] = [
self.coverage[code] = (
number_of_instructions,
[False] * number_of_instructions,
]
)
self.coverage[code][1][instruction_index] = True

@ -1,9 +1,10 @@
"""This module contains various utility conversion functions and constants for
LASER."""
import re
from typing import Dict, List, Union
from typing import Dict, List, Union, TYPE_CHECKING
import sha3 as _sha3
if TYPE_CHECKING:
from mythril.laser.ethereum.state.machine_state import MachineState
from mythril.laser.smt import BitVec, Bool, Expression, If, simplify, symbol_factory
@ -12,15 +13,6 @@ TT256M1 = 2 ** 256 - 1
TT255 = 2 ** 255
def sha3(seed: str) -> bytes:
"""
:param seed:
:return:
"""
return _sha3.keccak_256(bytes(seed)).digest()
def safe_decode(hex_encoded_string: str) -> bytes:
"""
@ -117,7 +109,9 @@ def get_concrete_int(item: Union[int, Expression]) -> int:
return value
def concrete_int_from_bytes(concrete_bytes: bytes, start_index: int) -> int:
def concrete_int_from_bytes(
concrete_bytes: List[Union[BitVec, int]], start_index: int
) -> int:
"""
:param concrete_bytes:

@ -7,7 +7,7 @@ import sqlite3
import time
from collections import defaultdict
from subprocess import PIPE, Popen
from typing import List
from typing import List, Dict, Set
from mythril.exceptions import CompilerError
@ -45,7 +45,7 @@ def synchronized(sync_lock):
class Singleton(type):
"""A metaclass type implementing the singleton pattern."""
_instances = {}
_instances = dict()
@synchronized(lock)
def __call__(cls, *args, **kwargs):
@ -60,6 +60,8 @@ class Singleton(type):
"""
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
print(type(cls), cls._instances[cls])
return cls._instances[cls]

@ -26,7 +26,7 @@ deps =
passenv = MYTHRIL_DIR = {homedir}
whitelist_externals = mkdir
commands =
mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --no-strict-optional .
mypy --follow-imports=silent --warn-unused-ignores --ignore-missing-imports --no-strict-optional mythril
mkdir -p {toxinidir}/tests/testdata/outputs_current/
mkdir -p {toxinidir}/tests/testdata/outputs_current_laser_result/
py.test -v \

Loading…
Cancel
Save