Apply better doc string formatting

pull/845/head
Dominik Muhs 6 years ago
parent a8f61a0f83
commit 5e0bcd3f9f
  1. 3
      mythril/analysis/call_helpers.py
  2. 3
      mythril/analysis/callgraph.py
  3. 5
      mythril/analysis/modules/base.py
  4. 4
      mythril/analysis/modules/delegatecall.py
  5. 25
      mythril/analysis/modules/dependence_on_predictable_vars.py
  6. 4
      mythril/analysis/modules/deprecated_ops.py
  7. 10
      mythril/analysis/modules/ether_thief.py
  8. 8
      mythril/analysis/modules/exceptions.py
  9. 10
      mythril/analysis/modules/external_calls.py
  10. 23
      mythril/analysis/modules/integer.py
  11. 7
      mythril/analysis/modules/multiple_sends.py
  12. 3
      mythril/analysis/modules/suicide.py
  13. 25
      mythril/analysis/modules/transaction_order_dependence.py
  14. 3
      mythril/analysis/modules/unchecked_retval.py
  15. 3
      mythril/analysis/ops.py
  16. 2
      mythril/analysis/report.py
  17. 3
      mythril/analysis/security.py
  18. 6
      mythril/analysis/symbolic.py
  19. 3
      mythril/analysis/traceexplore.py
  20. 8
      mythril/disassembler/asm.py
  21. 12
      mythril/disassembler/disassembly.py
  22. 6
      mythril/ethereum/evmcontract.py
  23. 26
      mythril/ethereum/interface/leveldb/accountindexing.py
  24. 20
      mythril/ethereum/interface/leveldb/client.py
  25. 15
      mythril/ethereum/interface/leveldb/eth_db.py
  26. 30
      mythril/ethereum/interface/leveldb/state.py
  27. 3
      mythril/ethereum/interface/rpc/constants.py
  28. 12
      mythril/ethereum/interface/rpc/exceptions.py
  29. 15
      mythril/ethereum/interface/rpc/utils.py
  30. 3
      mythril/ethereum/util.py
  31. 12
      mythril/exceptions.py
  32. 10
      mythril/interfaces/epic.py
  33. 25
      mythril/laser/ethereum/call.py
  34. 2
      mythril/laser/ethereum/cfg.py
  35. 3
      mythril/laser/ethereum/gas.py
  36. 17
      mythril/laser/ethereum/instructions.py
  37. 7
      mythril/laser/ethereum/keccak.py
  38. 2
      mythril/laser/ethereum/natives.py
  39. 16
      mythril/laser/ethereum/state/account.py
  40. 24
      mythril/laser/ethereum/state/annotation.py
  41. 19
      mythril/laser/ethereum/state/calldata.py
  42. 10
      mythril/laser/ethereum/state/constraints.py
  43. 6
      mythril/laser/ethereum/state/environment.py
  44. 14
      mythril/laser/ethereum/state/global_state.py
  45. 26
      mythril/laser/ethereum/state/machine_state.py
  46. 6
      mythril/laser/ethereum/state/memory.py
  47. 28
      mythril/laser/ethereum/state/world_state.py
  48. 8
      mythril/laser/ethereum/strategy/__init__.py
  49. 29
      mythril/laser/ethereum/strategy/basic.py
  50. 18
      mythril/laser/ethereum/svm.py
  51. 41
      mythril/laser/ethereum/taint_analysis.py
  52. 7
      mythril/laser/ethereum/transaction/concolic.py
  53. 9
      mythril/laser/ethereum/transaction/symbolic.py
  54. 15
      mythril/laser/ethereum/transaction/transaction_models.py
  55. 3
      mythril/laser/ethereum/util.py
  56. 33
      mythril/laser/smt/__init__.py
  57. 20
      mythril/laser/smt/array.py
  58. 3
      mythril/laser/smt/bitvec.py
  59. 3
      mythril/laser/smt/bool.py
  60. 7
      mythril/laser/smt/expression.py
  61. 26
      mythril/laser/smt/solver.py
  62. 5
      mythril/mythril.py
  63. 3
      mythril/solidity/soliditycontract.py
  64. 3
      mythril/support/loader.py
  65. 31
      mythril/support/signatures.py
  66. 3
      mythril/support/truffle.py
  67. 3
      mythril/version.py
  68. 14
      setup.py
  69. 8
      tests/__init__.py
  70. 16
      tests/evmcontract_test.py
  71. 4
      tests/native_test.py
  72. 12
      tests/report_test.py
  73. 8
      tests/rpc_test.py

@ -1,4 +1,5 @@
"""This module provides helper functions for the analysis modules to deal with call functionality."""
"""This module provides helper functions for the analysis modules to deal with
call functionality."""
from typing import Union
from mythril.analysis.ops import VarType, Call, get_variable

@ -1,4 +1,5 @@
"""This module contains the configuration and functions to create call graphs."""
"""This module contains the configuration and functions to create call
graphs."""
import re

@ -1,4 +1,5 @@
"""This module contains the base class for all user-defined detection modules."""
"""This module contains the base class for all user-defined detection
modules."""
import logging
from typing import List
@ -40,7 +41,7 @@ class DetectionModule:
self.entrypoint = entrypoint
def execute(self, statespace):
""" The entry point for execution, which is being called by Mythril.
"""The entry point for execution, which is being called by Mythril.
:param statespace:
:return:

@ -18,9 +18,7 @@ class DelegateCallModule(DetectionModule):
"""This module detects calldata being forwarded using DELEGATECALL."""
def __init__(self):
"""
"""
""""""
super().__init__(
name="DELEGATECALL Usage in Fallback Function",
swc_id=DELEGATECALL_TO_UNTRUSTED_CONTRACT,

@ -1,4 +1,5 @@
"""This module contains the detection code for predictable variable dependence."""
"""This module contains the detection code for predictable variable
dependence."""
import re
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.analysis.ops import Call, VarType
@ -14,12 +15,11 @@ log = logging.getLogger(__name__)
class PredictableDependenceModule(DetectionModule):
"""This module detects whether Ether is sent using predictable parameters."""
"""This module detects whether Ether is sent using predictable
parameters."""
def __init__(self):
"""
"""
""""""
super().__init__(
name="Dependence of Predictable Variables",
swc_id="{} {}".format(TIMESTAMP_DEPENDENCE, PREDICTABLE_VARS_DEPENDENCE),
@ -169,12 +169,15 @@ def _analyze_states(state: GlobalState) -> list:
r = re.search(r"storage_([a-z0-9_&^]+)", str(constraint))
if r: # block.blockhash(storage_0)
"""
We actually can do better here by adding a constraint blockhash_block_storage_0 == 0
and checking model satisfiability. When this is done, severity can be raised
from 'Informational' to 'Warning'.
Checking that storage at given index can be tainted is not necessary, since it usually contains
block.number of the 'commit' transaction in commit-reveal workflow.
"""We actually can do better here by adding a constraint
blockhash_block_storage_0 == 0 and checking model
satisfiability.
When this is done, severity can be raised from
'Informational' to 'Warning'. Checking that storage
at given index can be tainted is not necessary,
since it usually contains block.number of the
'commit' transaction in commit-reveal workflow.
"""
index = r.group(1)

@ -60,9 +60,7 @@ class DeprecatedOperationsModule(DetectionModule):
"""This module checks for the usage of deprecated op codes."""
def __init__(self):
"""
"""
""""""
super().__init__(
name="Deprecated Operations",
swc_id=DEPRICATED_FUNCTIONS_USAGE,

@ -1,4 +1,5 @@
"""This module contains the detection code for unauthorized ether withdrawal."""
"""This module contains the detection code for unauthorized ether
withdrawal."""
from mythril.analysis.ops import *
from mythril.analysis import solver
from mythril.analysis.report import Issue
@ -83,12 +84,11 @@ def _analyze_state(state):
class EtherThief(DetectionModule):
"""This module search for cases where Ether can be withdrawn to a user-specified address."""
"""This module search for cases where Ether can be withdrawn to a user-
specified address."""
def __init__(self):
"""
"""
""""""
super().__init__(
name="Ether Thief",
swc_id=UNPROTECTED_ETHER_WITHDRAWAL,

@ -56,14 +56,10 @@ def _analyze_state(state) -> list:
class ReachableExceptionsModule(DetectionModule):
"""
"""
""""""
def __init__(self):
"""
"""
""""""
super().__init__(
name="Reachable Exceptions",
swc_id=ASSERT_VIOLATION,

@ -1,4 +1,5 @@
"""This module contains the detection code for potentially insecure low-level calls."""
"""This module contains the detection code for potentially insecure low-level
calls."""
from mythril.analysis.report import Issue
from mythril.analysis import solver
from mythril.analysis.swc_data import REENTRANCY
@ -96,12 +97,11 @@ def _analyze_state(state):
class ExternalCalls(DetectionModule):
"""This module searches for low level calls (e.g. call.value()) that forward all gas to the callee."""
"""This module searches for low level calls (e.g. call.value()) that
forward all gas to the callee."""
def __init__(self):
"""
"""
""""""
super().__init__(
name="External calls",
swc_id=REENTRANCY,

@ -1,4 +1,5 @@
"""This module contains the detection code for integer overflows and underflows."""
"""This module contains the detection code for integer overflows and
underflows."""
from mythril.analysis import solver
from mythril.analysis.report import Issue
from mythril.analysis.swc_data import INTEGER_OVERFLOW_AND_UNDERFLOW
@ -26,9 +27,7 @@ class IntegerOverflowUnderflowModule(DetectionModule):
"""This module searches for integer over- and underflows."""
def __init__(self):
"""
"""
""""""
super().__init__(
name="Integer Overflow and Underflow",
swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW,
@ -41,7 +40,7 @@ class IntegerOverflowUnderflowModule(DetectionModule):
)
def execute(self, statespace):
"""Executes analysis module for integer underflow and integer overflow
"""Executes analysis module for integer underflow and integer overflow.
:param statespace: Statespace to analyse
:return: Found issues
@ -137,7 +136,7 @@ class IntegerOverflowUnderflowModule(DetectionModule):
def _verify_integer_overflow(
self, statespace, node, expr, state, model, constraint, op0, op1
):
""" Verifies existence of integer overflow
"""Verifies existence of integer overflow.
:param statespace:
:param node:
@ -178,8 +177,7 @@ class IntegerOverflowUnderflowModule(DetectionModule):
return None
def _check_integer_underflow(self, statespace, state, node):
"""
Checks for integer underflow
"""Checks for integer underflow.
:param statespace:
:param state: state from node to examine
@ -267,7 +265,7 @@ class IntegerOverflowUnderflowModule(DetectionModule):
@staticmethod
def _check_jumpi(state, taint_result):
""" Check if conditional jump is dependent on the result of expression
"""Check if conditional jump is dependent on the result of expression.
:param state:
:param taint_result:
@ -278,7 +276,7 @@ class IntegerOverflowUnderflowModule(DetectionModule):
@staticmethod
def _check_sstore(state, taint_result):
""" Check if store operation is dependent on the result of expression
"""Check if store operation is dependent on the result of expression.
:param state:
:param taint_result:
@ -298,9 +296,8 @@ class IntegerOverflowUnderflowModule(DetectionModule):
depth=0,
max_depth=64,
):
"""
Checks the statespace for children states, with JUMPI or SSTORE instuctions,
for dependency on expression
"""Checks the statespace for children states, with JUMPI or SSTORE
instuctions, for dependency on expression.
:param statespace: The statespace to explore
:param node: Current node to explore from

@ -1,4 +1,5 @@
"""This module contains the detection code to find multiple sends occurring in a single transaction."""
"""This module contains the detection code to find multiple sends occurring in
a single transaction."""
from mythril.analysis.report import Issue
from mythril.analysis.swc_data import MULTIPLE_SENDS
from mythril.analysis.modules.base import DetectionModule
@ -9,9 +10,7 @@ class MultipleSendsModule(DetectionModule):
"""This module checks for multiple sends in a single transaction."""
def __init__(self):
"""
"""
""""""
super().__init__(
name="Multiple Sends",
swc_id=MULTIPLE_SENDS,

@ -59,7 +59,8 @@ def _analyze_state(state):
class SuicideModule(DetectionModule):
"""This module checks if the contact can be 'accidentally' killed by anyone."""
"""This module checks if the contact can be 'accidentally' killed by
anyone."""
def __init__(self):
super().__init__(

@ -1,4 +1,5 @@
"""This module contains the detection code to find the existence of transaction order dependence."""
"""This module contains the detection code to find the existence of transaction
order dependence."""
import logging
import re
import copy
@ -31,7 +32,7 @@ class TxOrderDependenceModule(DetectionModule):
)
def execute(self, statespace):
""" Executes the analysis module
"""Executes the analysis module.
:param statespace:
:return:
@ -76,7 +77,7 @@ class TxOrderDependenceModule(DetectionModule):
# TODO: move to __init__ or util module
@staticmethod
def _get_states_with_opcode(statespace, opcode):
""" Gets all (state, node) tuples in statespace with opcode
"""Gets all (state, node) tuples in statespace with opcode.
:param statespace:
:param opcode:
@ -89,7 +90,8 @@ class TxOrderDependenceModule(DetectionModule):
@staticmethod
def _dependent_on_storage(expression):
""" Checks if expression is dependent on a storage symbol and returns the influencing storages
"""Checks if expression is dependent on a storage symbol and returns
the influencing storages.
:param expression:
:return:
@ -99,8 +101,8 @@ class TxOrderDependenceModule(DetectionModule):
@staticmethod
def _get_storage_variable(storage, state):
"""
Get storage z3 object given storage name and the state
"""Get storage z3 object given storage name and the state.
:param storage: storage name example: storage_0
:param state: state to retrieve the variable from
:return: z3 object representing storage
@ -112,7 +114,7 @@ class TxOrderDependenceModule(DetectionModule):
return None
def _can_change(self, constraints, variable):
""" Checks if the variable can change given some constraints
"""Checks if the variable can change given some constraints.
:param constraints:
:param variable:
@ -133,7 +135,8 @@ class TxOrderDependenceModule(DetectionModule):
return False
def _get_influencing_storages(self, call):
""" Examines a Call object and returns an iterator of all storages that influence the call value or direction
"""Examines a Call object and returns an iterator of all storages that
influence the call value or direction.
:param call:
"""
@ -156,7 +159,7 @@ class TxOrderDependenceModule(DetectionModule):
yield storage
def _get_influencing_sstores(self, statespace, interesting_storages):
""" Gets sstore (state, node) tuples that write to interesting_storages
"""Gets sstore (state, node) tuples that write to interesting_storages.
:param statespace:
:param interesting_storages:
@ -175,8 +178,8 @@ class TxOrderDependenceModule(DetectionModule):
# TODO: remove
@staticmethod
def _try_constraints(constraints, new_constraints):
"""
Tries new constraints
"""Tries new constraints.
:param constraints:
:param new_constraints:
:return Model if satisfiable otherwise None

@ -1,4 +1,5 @@
"""This module contains detection code to find occurrences of calls whose return value remains unchecked."""
"""This module contains detection code to find occurrences of calls whose
return value remains unchecked."""
from mythril.analysis.report import Issue
from mythril.analysis.swc_data import UNCHECKED_RET_VAL
from mythril.analysis.modules.base import DetectionModule

@ -1,4 +1,5 @@
"""This module contains various helper methods for dealing with EVM operations."""
"""This module contains various helper methods for dealing with EVM
operations."""
from mythril.laser.smt import simplify
from enum import Enum
from mythril.laser.ethereum import util

@ -156,7 +156,7 @@ class Report:
return json.dumps(result, sort_keys=True)
def as_swc_standard_format(self):
""" Format defined for integration and correlation
"""Format defined for integration and correlation.
:return:
"""

@ -1,4 +1,5 @@
"""This module contains functionality for hooking in detection modules and executing them."""
"""This module contains functionality for hooking in detection modules and
executing them."""
from collections import defaultdict
from ethereum.opcodes import opcodes
from mythril.analysis import modules

@ -1,4 +1,5 @@
"""This module contains a wrapper around LASER for extended analysis purposes."""
"""This module contains a wrapper around LASER for extended analysis
purposes."""
from mythril.analysis.security import get_detection_module_hooks
from mythril.laser.ethereum import svm
from mythril.laser.ethereum.state.account import Account
@ -16,7 +17,8 @@ from mythril.laser.ethereum.strategy.basic import (
class SymExecWrapper:
"""Wrapper class for the LASER Symbolic virtual machine.
Symbolically executes the code and does a bit of pre-analysis for convenience.
Symbolically executes the code and does a bit of pre-analysis for
convenience.
"""
def __init__(

@ -1,4 +1,5 @@
"""This module provides a function to convert a state space into a set of state nodes and transition edges."""
"""This module provides a function to convert a state space into a set of state
nodes and transition edges."""
from z3 import Z3Exception
from mythril.laser.smt import simplify
from mythril.laser.ethereum.svm import NodeFlags

@ -1,4 +1,5 @@
"""This module contains various helper classes and functions to deal with EVM code disassembly."""
"""This module contains various helper classes and functions to deal with EVM
code disassembly."""
import re
from collections import Generator
@ -12,7 +13,7 @@ opcodes[254] = ["ASSERT_FAIL", 0, 0, 0]
class EvmInstruction:
""" Model to hold the information of the disassembly."""
"""Model to hold the information of the disassembly."""
def __init__(self, address, op_code, argument=None):
self.address = address
@ -60,7 +61,8 @@ def get_opcode_from_name(operation_name: str) -> int:
def find_op_code_sequence(pattern: list, instruction_list: list) -> Generator:
"""Returns all indices in instruction_list that point to instruction sequences following a pattern.
"""Returns all indices in instruction_list that point to instruction
sequences following a pattern.
:param pattern: The pattern to look for, e.g. [["PUSH1", "PUSH2"], ["EQ"]] where ["PUSH1", "EQ"] satisfies pattern
:param instruction_list: List of instructions to look in

@ -5,8 +5,7 @@ from mythril.support.signatures import SignatureDB
class Disassembly(object):
"""
Disassembly class
"""Disassembly class.
Stores bytecode, and its disassembly.
Additionally it will gather the following information on the existing functions in the disassembled code:
@ -58,10 +57,11 @@ class Disassembly(object):
def get_function_info(
index: int, instruction_list: list, signature_database: SignatureDB
) -> (str, int, str):
"""
Finds the function information for a call table entry
Solidity uses the first 4 bytes of the calldata to indicate which function the message call should execute
The generated code that directs execution to the correct function looks like this:
"""Finds the function information for a call table entry Solidity uses the
first 4 bytes of the calldata to indicate which function the message call
should execute The generated code that directs execution to the correct
function looks like this:
- PUSH function_hash
- EQ
- PUSH entry_point

@ -1,4 +1,5 @@
"""This module contains the class representing EVM contracts, aka Smart Contracts."""
"""This module contains the class representing EVM contracts, aka Smart
Contracts."""
from mythril.disassembler.disassembly import Disassembly
from ethereum import utils
import persistent
@ -6,7 +7,8 @@ import re
class EVMContract(persistent.Persistent):
"""This class represents an address with associated code (Smart Contract)."""
"""This class represents an address with associated code (Smart
Contract)."""
def __init__(
self, code="", creation_code="", name="Unknown", enable_online_lookup=False

@ -1,7 +1,7 @@
"""This module contains account indexing functionality.
This includes a sedes class for lists, account storage receipts for LevelDB
and a class for updating account addresses.
This includes a sedes class for lists, account storage receipts for
LevelDB and a class for updating account addresses.
"""
import logging
from mythril import ethereum
@ -20,6 +20,7 @@ BATCH_SIZE = 8 * 4096
class CountableList(object):
"""A sedes for lists of arbitrary length.
:param element_sedes: when (de-)serializing a list, this sedes will be applied to all of its elements
"""
@ -50,9 +51,7 @@ class CountableList(object):
class ReceiptForStorage(rlp.Serializable):
"""
Receipt format stored in levelDB
"""
"""Receipt format stored in levelDB."""
fields = [
("state_root", binary),
@ -66,9 +65,7 @@ class ReceiptForStorage(rlp.Serializable):
class AccountIndexer(object):
"""
Updates address index
"""
"""Updates address index."""
def __init__(self, ethDB):
self.db = ethDB
@ -78,9 +75,8 @@ class AccountIndexer(object):
self.updateIfNeeded()
def get_contract_by_hash(self, contract_hash):
"""
get mapped contract_address by its hash, if not found try indexing
"""
"""get mapped contract_address by its hash, if not found try
indexing."""
contract_address = self.db.reader._get_address_by_hash(contract_hash)
if contract_address is not None:
return contract_address
@ -89,9 +85,7 @@ class AccountIndexer(object):
raise AddressNotFoundError
def _process(self, startblock):
"""
Processesing method
"""
"""Processesing method."""
log.debug("Processing blocks %d to %d" % (startblock, startblock + BATCH_SIZE))
addresses = []
@ -113,9 +107,7 @@ class AccountIndexer(object):
return addresses
def updateIfNeeded(self):
"""
update address index
"""
"""update address index."""
headBlock = self.db.reader._get_head_block()
if headBlock is not None:
# avoid restarting search if head block is same & we already initialized

@ -158,9 +158,7 @@ class LevelDBReader(object):
class LevelDBWriter(object):
"""
level db writing interface
"""
"""level db writing interface."""
def __init__(self, db):
"""
@ -183,7 +181,7 @@ class LevelDBWriter(object):
self.wb = self.db.write_batch()
def _commit_batch(self):
"""Commit a batch"""
"""Commit a batch."""
self.wb.write()
def _store_account_address(self, address):
@ -196,9 +194,7 @@ class LevelDBWriter(object):
class EthLevelDB(object):
"""
Go-Ethereum LevelDB client class
"""
"""Go-Ethereum LevelDB client class."""
def __init__(self, path):
"""
@ -235,10 +231,12 @@ class EthLevelDB(object):
try:
address = _encode_hex(indexer.get_contract_by_hash(address_hash))
except AddressNotFoundError:
"""
The hash->address mapping does not exist in our index. If the index is up-to-date, this likely means
that the contract was created by an internal transaction. Skip this contract as right now we don't
have a good solution for this.
"""The hash->address mapping does not exist in our index.
If the index is up-to-date, this likely means that
the contract was created by an internal transaction.
Skip this contract as right now we don't have a good
solution for this.
"""
continue

@ -1,4 +1,5 @@
"""This module contains the ETH_DB class, which the base database used by pyethereum."""
"""This module contains the ETH_DB class, which the base database used by
pyethereum."""
import plyvel
from ethereum.db import BaseDB
@ -10,19 +11,13 @@ class ETH_DB(BaseDB):
self.db = plyvel.DB(path)
def get(self, key):
"""
gets value for key
"""
"""gets value for key."""
return self.db.get(key)
def put(self, key, value):
"""
puts value for key
"""
"""puts value for key."""
self.db.put(key, value)
def write_batch(self):
"""
start writing a batch
"""
"""start writing a batch."""
return self.db.write_batch()

@ -48,9 +48,7 @@ STATE_DEFAULTS = {
class Account(rlp.Serializable):
"""
adjusted account from ethereum.state
"""
"""adjusted account from ethereum.state."""
fields = [
("nonce", big_endian_int),
@ -82,14 +80,11 @@ class Account(rlp.Serializable):
@property
def code(self):
"""
code rlp data
"""
"""code rlp data."""
return self.db.get(self.code_hash)
def get_storage_data(self, key):
"""
get storage data
"""get storage data.
:param key:
:return:
@ -103,8 +98,8 @@ class Account(rlp.Serializable):
@classmethod
def blank_account(cls, db, addr, initial_nonce=0):
"""
creates a blank account
"""creates a blank account.
:param db:
:param addr:
:param initial_nonce:
@ -116,17 +111,15 @@ class Account(rlp.Serializable):
return o
def is_blank(self):
"""
checks if is a blank account
"""checks if is a blank account.
:return:
"""
return self.nonce == 0 and self.balance == 0 and self.code_hash == BLANK_HASH
class State:
"""
adjusted state from ethereum.state
"""
"""adjusted state from ethereum.state."""
def __init__(self, db, root):
"""
@ -141,7 +134,8 @@ class State:
self.cache = {}
def get_and_cache_account(self, addr):
"""Gets and caches an account for an addres, creates blank if not found
"""Gets and caches an account for an addres, creates blank if not
found.
:param addr:
:return:
@ -165,9 +159,7 @@ class State:
return o
def get_all_accounts(self):
"""
iterates through trie to and yields non-blank leafs as accounts
"""
"""iterates through trie to and yields non-blank leafs as accounts."""
for address_hash, rlpdata in self.secure_trie.trie.iter_branch():
if rlpdata != trie.BLANK_NODE:
yield rlp.decode(rlpdata, Account, db=self.db, address=address_hash)

@ -1,4 +1,5 @@
"""This file contains constants used used by the Ethereum JSON RPC interface."""
"""This file contains constants used used by the Ethereum JSON RPC
interface."""
BLOCK_TAG_EARLIEST = "earliest"
BLOCK_TAG_LATEST = "latest"
BLOCK_TAG_PENDING = "pending"

@ -8,24 +8,28 @@ class EthJsonRpcError(Exception):
class ConnectionError(EthJsonRpcError):
"""An RPC exception denoting there was an error in connecting to the RPC instance."""
"""An RPC exception denoting there was an error in connecting to the RPC
instance."""
pass
class BadStatusCodeError(EthJsonRpcError):
"""An RPC exception denoting a bad status code returned by the RPC instance."""
"""An RPC exception denoting a bad status code returned by the RPC
instance."""
pass
class BadJsonError(EthJsonRpcError):
"""An RPC exception denoting that the RPC instance returned a bad JSON object."""
"""An RPC exception denoting that the RPC instance returned a bad JSON
object."""
pass
class BadResponseError(EthJsonRpcError):
"""An RPC exception denoting that the RPC instance returned a bad response."""
"""An RPC exception denoting that the RPC instance returned a bad
response."""
pass

@ -1,10 +1,10 @@
"""This module contains various utility functions regarding the RPC data format and validation."""
"""This module contains various utility functions regarding the RPC data format
and validation."""
from .constants import BLOCK_TAGS
def hex_to_dec(x):
"""
Convert hex to decimal
"""Convert hex to decimal.
:param x:
:return:
@ -13,9 +13,8 @@ def hex_to_dec(x):
def clean_hex(d):
"""
Convert decimal to hex and remove the "L" suffix that is appended to large
numbers
"""Convert decimal to hex and remove the "L" suffix that is appended to
large numbers.
:param d:
:return:
@ -38,7 +37,7 @@ def validate_block(block):
def wei_to_ether(wei):
"""Convert wei to ether
"""Convert wei to ether.
:param wei:
:return:
@ -47,7 +46,7 @@ def wei_to_ether(wei):
def ether_to_wei(ether):
"""Convert ether to wei
"""Convert ether to wei.
:param ether:
:return:

@ -1,4 +1,5 @@
"""This module contains various utility functions regarding unit conversion and solc integration."""
"""This module contains various utility functions regarding unit conversion and
solc integration."""
from ethereum.abi import encode_abi, encode_int
from ethereum.utils import zpad
from ethereum.abi import method_id

@ -14,24 +14,28 @@ class CompilerError(MythrilBaseException):
class UnsatError(MythrilBaseException):
"""A Mythril exception denoting the unsatisfiability of a series of constraints."""
"""A Mythril exception denoting the unsatisfiability of a series of
constraints."""
pass
class NoContractFoundError(MythrilBaseException):
"""A Mythril exception denoting that a given contract file was not found."""
"""A Mythril exception denoting that a given contract file was not
found."""
pass
class CriticalError(MythrilBaseException):
"""A Mythril exception denoting an unknown critical error has been encountered."""
"""A Mythril exception denoting an unknown critical error has been
encountered."""
pass
class AddressNotFoundError(MythrilBaseException):
"""A Mythril exception denoting the given smart contract address was not found."""
"""A Mythril exception denoting the given smart contract address was not
found."""
pass

@ -21,9 +21,7 @@ PY3 = sys.version_info >= (3,)
# Reset terminal colors at exit
def reset():
"""
"""
""""""
sys.stdout.write("\x1b[0m")
sys.stdout.flush()
@ -53,7 +51,7 @@ COLOR_ANSI = (
class LolCat(object):
"""Cats lel"""
"""Cats lel."""
def __init__(self, mode=256, output=sys.stdout):
self.mode = mode
@ -193,9 +191,7 @@ class LolCat(object):
def detect_mode(term_hint="xterm-256color"):
"""
Poor-mans color mode detection.
"""
"""Poor-mans color mode detection."""
if "ANSICON" in os.environ:
return 16
elif os.environ.get("ConEmuANSI", "OFF") == "ON":

@ -1,7 +1,6 @@
"""
This module contains the business logic used by Instruction in instructions.py
to get the necessary elements from the stack and determine the parameters for the new global state.
"""
"""This module contains the business logic used by Instruction in
instructions.py to get the necessary elements from the stack and determine the
parameters for the new global state."""
import logging
from typing import Union
@ -28,9 +27,9 @@ log = logging.getLogger(__name__)
def get_call_parameters(
global_state: GlobalState, dynamic_loader: DynLoader, with_value=False
):
"""
Gets call parameters from global state
Pops the values from the stack and determines output parameters
"""Gets call parameters from global state Pops the values from the stack
and determines output parameters.
:param global_state: state to look in
:param dynamic_loader: dynamic loader to use
:param with_value: whether to pop the value argument from the stack
@ -71,8 +70,8 @@ def get_callee_address(
dynamic_loader: DynLoader,
symbolic_to_address: Expression,
):
"""
Gets the address of the callee
"""Gets the address of the callee.
:param global_state: state to look in
:param dynamic_loader: dynamic loader to use
:param symbolic_to_address: The (symbolic) callee address
@ -114,8 +113,8 @@ def get_callee_address(
def get_callee_account(
global_state: GlobalState, callee_address: str, dynamic_loader: DynLoader
):
"""
Gets the callees account from the global_state
"""Gets the callees account from the global_state.
:param global_state: state to look in
:param callee_address: address of the callee
:param dynamic_loader: dynamic loader to use
@ -158,8 +157,8 @@ def get_call_data(
memory_start: Union[int, Expression],
memory_size: Union[int, Expression],
):
"""
Gets call_data from the global_state
"""Gets call_data from the global_state.
:param global_state: state to look in
:param memory_start: Start index
:param memory_size: Size

@ -1,4 +1,4 @@
"""This module """
"""This module."""
from flags import Flags
from enum import Enum
from typing import Dict

@ -1,4 +1,5 @@
"""This module contains functions for dynamic gas calculation and a gas cost table."""
"""This module contains functions for dynamic gas calculation and a gas cost
table."""
from ethereum import opcodes
from ethereum.utils import ceil32

@ -1,4 +1,5 @@
"""This module contains a representation class for EVM instructions and transitions between them."""
"""This module contains a representation class for EVM instructions and
transitions between them."""
import binascii
import logging
@ -63,9 +64,10 @@ keccak_function_manager = KeccakFunctionManager()
class StateTransition(object):
"""Decorator that handles global state copy and original return.
This decorator calls the decorated instruction mutator function on a copy of the state that
is passed to it. After the call, the resulting new states' program counter is automatically
incremented if `increment_pc=True`.
This decorator calls the decorated instruction mutator function on a
copy of the state that is passed to it. After the call, the
resulting new states' program counter is automatically incremented
if `increment_pc=True`.
"""
def __init__(self, increment_pc=True, enable_gas=True):
@ -153,9 +155,8 @@ class StateTransition(object):
class Instruction:
"""
Instruction class is used to mutate a state according to the current instruction
"""
"""Instruction class is used to mutate a state according to the current
instruction."""
def __init__(self, op_code: str, dynamic_loader: DynLoader):
"""
@ -167,7 +168,7 @@ class Instruction:
self.op_code = op_code.upper()
def evaluate(self, global_state: GlobalState, post=False) -> List[GlobalState]:
""" Performs the mutation for this instruction
"""Performs the mutation for this instruction.
:param global_state:
:param post:

@ -1,4 +1,5 @@
"""This module contains a function manager to deal with symbolic Keccak values."""
"""This module contains a function manager to deal with symbolic Keccak
values."""
from mythril.laser.smt import Expression
@ -6,9 +7,7 @@ class KeccakFunctionManager:
"""A keccak function manager for symbolic expressions."""
def __init__(self):
"""
"""
""""""
self.keccak_expression_mapping = {}
def is_keccak(self, expression: Expression) -> bool:

@ -124,7 +124,7 @@ def identity(data: Union[bytes, str, List[int]]) -> bytes:
def native_contracts(address: int, data: BaseCalldata):
"""Takes integer address 1, 2, 3, 4
"""Takes integer address 1, 2, 3, 4.
:param address:
:param data:

@ -12,13 +12,11 @@ from mythril.disassembler.disassembly import Disassembly
class Storage:
"""
Storage class represents the storage of an Account
"""
"""Storage class represents the storage of an Account."""
def __init__(self, concrete=False, address=None, dynamic_loader=None):
"""
Constructor for Storage
"""Constructor for Storage.
:param concrete: bool indicating whether to interpret uninitialized storage as concrete versus symbolic
"""
self._storage = {}
@ -62,9 +60,7 @@ class Storage:
class Account:
"""
Account class representing ethereum accounts
"""
"""Account class representing ethereum accounts."""
def __init__(
self,
@ -75,8 +71,8 @@ class Account:
concrete_storage=False,
dynamic_loader=None,
):
"""
Constructor for account
"""Constructor for account.
:param address: Address of the account
:param code: The contract code of the account
:param contract_name: The name associated with the account

@ -1,20 +1,21 @@
"""This module includes classes used for annotating trace information.
This includes the base StateAnnotation class, as well as an adaption, which will not be
copied on every new state.
This includes the base StateAnnotation class, as well as an adaption,
which will not be copied on every new state.
"""
class StateAnnotation:
"""
The StateAnnotation class is used to persist information over traces. This allows modules to reason about traces
without the need to traverse the state space themselves.
"""The StateAnnotation class is used to persist information over traces.
This allows modules to reason about traces without the need to
traverse the state space themselves.
"""
@property
def persist_to_world_state(self) -> bool:
"""
If this function returns true then laser will also annotate the world state.
"""If this function returns true then laser will also annotate the
world state.
If you want annotations to persist through different user initiated message call transactions
then this should be enabled.
@ -25,10 +26,11 @@ class StateAnnotation:
class NoCopyAnnotation(StateAnnotation):
"""
This class provides a base annotation class for annotations that shouldn't be copied on every new state.
Rather the same object should be propagated.
This is very useful if you are looking to analyze a property over multiple substates
"""This class provides a base annotation class for annotations that
shouldn't be copied on every new state.
Rather the same object should be propagated. This is very useful if
you are looking to analyze a property over multiple substates
"""
def __copy__(self):

@ -18,10 +18,8 @@ class CalldataType(Enum):
class BaseCalldata:
"""
Base calldata class
This represents the calldata provided when sending a transaction to a contract
"""
"""Base calldata class This represents the calldata provided when sending a
transaction to a contract."""
def __init__(self, tx_id):
"""
@ -42,7 +40,7 @@ class BaseCalldata:
return result
def get_word_at(self, offset: int) -> Expression:
""" Gets word at offset
"""Gets word at offset.
:param offset:
:return:
@ -94,14 +92,14 @@ class BaseCalldata:
@property
def size(self) -> Union[Expression, int]:
""" Returns the exact size of this calldata, this is not normalized
"""Returns the exact size of this calldata, this is not normalized.
:return: unnormalized call data size
"""
raise NotImplementedError()
def concrete(self, model: Model) -> list:
""" Returns a concrete version of the calldata using the provided model
"""Returns a concrete version of the calldata using the provided model.
:param model:
"""
@ -112,8 +110,7 @@ class ConcreteCalldata(BaseCalldata):
"""A concrete call data representation."""
def __init__(self, tx_id: int, calldata: list):
"""
Initializes the ConcreteCalldata object.
"""Initializes the ConcreteCalldata object.
:param tx_id: Id of the transaction that the calldata is for.
:param calldata: The concrete calldata content
@ -257,8 +254,8 @@ class BasicSymbolicCalldata(BaseCalldata):
"""A basic class representing symbolic call data."""
def __init__(self, tx_id: int):
"""
Initializes the SymbolicCalldata object
"""Initializes the SymbolicCalldata object.
:param tx_id: Id of the transaction that the calldata is for.
"""
self._reads = []

@ -1,10 +1,12 @@
"""This module contains the class used to represent state-change constraints in the call graph."""
"""This module contains the class used to represent state-change constraints in
the call graph."""
class Constraints(list):
"""
This class should maintain a solver and it's constraints, This class tries to make the Constraints() object
as a simple list of constraints with some background processing.
"""This class should maintain a solver and it's constraints, This class
tries to make the Constraints() object as a simple list of constraints with
some background processing.
TODO: add the solver to this class after callback refactor
"""

@ -1,4 +1,5 @@
"""This module contains the representation for an execution state's environment."""
"""This module contains the representation for an execution state's
environment."""
from typing import Dict
from z3 import ExprRef, BitVecVal
@ -9,7 +10,8 @@ from mythril.laser.ethereum.state.calldata import CalldataType, BaseCalldata
class Environment:
"""The environment class represents the current execution environment for the symbolic executor."""
"""The environment class represents the current execution environment for
the symbolic executor."""
def __init__(
self,

@ -12,9 +12,7 @@ from mythril.laser.ethereum.state.annotation import StateAnnotation
class GlobalState:
"""
GlobalState represents the current globalstate
"""
"""GlobalState represents the current globalstate."""
def __init__(
self,
@ -26,7 +24,7 @@ class GlobalState:
last_return_data=None,
annotations=None,
):
""" Constructor for GlobalState
"""Constructor for GlobalState.
:param world_state:
:param environment:
@ -76,7 +74,7 @@ class GlobalState:
# TODO: remove this, as two instructions are confusing
def get_current_instruction(self) -> Dict:
""" Gets the current instruction for this GlobalState
"""Gets the current instruction for this GlobalState.
:return:
"""
@ -135,9 +133,9 @@ class GlobalState:
return self._annotations
def get_annotations(self, annotation_type: type) -> Iterable[StateAnnotation]:
"""
Filters annotations for the queried annotation type. Designed particularly for
modules with annotations: globalstate.get_annotations(MySpecificModuleAnnotation)
"""Filters annotations for the queried annotation type. Designed
particularly for modules with annotations:
globalstate.get_annotations(MySpecificModuleAnnotation)
:param annotation_type: The type to filter annotations for
:return: filter of matching annotations

@ -1,4 +1,5 @@
"""This module contains a representation of the EVM's machine state and its stack."""
"""This module contains a representation of the EVM's machine state and its
stack."""
from copy import copy
from typing import Union, Any, List, Dict
@ -15,9 +16,7 @@ from mythril.laser.ethereum.state.memory import Memory
class MachineStack(list):
"""
Defines EVM stack, overrides the default list to handle overflows
"""
"""Defines EVM stack, overrides the default list to handle overflows."""
STACK_LIMIT = 1024
@ -68,24 +67,23 @@ class MachineStack(list):
)
def __add__(self, other):
"""Implement list concatenation if needed
"""Implement list concatenation if needed.
:param other:
"""
raise NotImplementedError("Implement this if needed")
def __iadd__(self, other):
"""
Implement list concatenation if needed
"""Implement list concatenation if needed.
:param other:
"""
raise NotImplementedError("Implement this if needed")
class MachineState:
"""
MachineState represents current machine state also referenced to as \mu
"""
"""MachineState represents current machine state also referenced to as
\mu."""
def __init__(
self,
@ -98,7 +96,7 @@ class MachineState:
max_gas_used=0,
min_gas_used=0,
):
""" Constructor for machineState
"""Constructor for machineState.
:param gas_limit:
:param pc:
@ -153,7 +151,7 @@ class MachineState:
raise OutOfGasException()
def mem_extend(self, start: int, size: int) -> None:
"""Extends the memory of this machine state
"""Extends the memory of this machine state.
:param start: Start of memory extension
:param size: Size of memory extension
@ -167,7 +165,7 @@ class MachineState:
self.memory.extend(m_extend)
def memory_write(self, offset: int, data: List[int]) -> None:
""" Writes data to memory starting at offset
"""Writes data to memory starting at offset.
:param offset:
:param data:
@ -176,7 +174,7 @@ class MachineState:
self.memory[offset : offset + len(data)] = data
def pop(self, amount=1) -> Union[BitVec, List[BitVec]]:
""" Pops amount elements from the stack
"""Pops amount elements from the stack.
:param amount:
:return:

@ -17,9 +17,7 @@ class Memory:
"""A class representing contract memory with random access."""
def __init__(self):
"""
"""
""""""
self._memory = []
def __len__(self):
@ -37,7 +35,7 @@ class Memory:
self._memory.extend(bytearray(size))
def get_word_at(self, index: int) -> Union[int, BitVec]:
"""Access a word from a specified memory index
"""Access a word from a specified memory index.
:param index: integer representing the index to access
:return: 32 byte word at the specified index

@ -8,15 +8,13 @@ from mythril.laser.ethereum.state.annotation import StateAnnotation
class WorldState:
"""
The WorldState class represents the world state as described in the yellow paper
"""
"""The WorldState class represents the world state as described in the
yellow paper."""
def __init__(
self, transaction_sequence=None, annotations: List[StateAnnotation] = None
) -> None:
"""
Constructor for the world state. Initializes the accounts record
"""Constructor for the world state. Initializes the accounts record.
:param transaction_sequence:
:param annotations:
@ -27,8 +25,7 @@ class WorldState:
self._annotations = annotations or []
def __getitem__(self, item: str) -> Account:
"""
Gets an account from the worldstate using item as key
"""Gets an account from the worldstate using item as key.
:param item: Address of the account to get
:return: Account associated with the address
@ -52,8 +49,7 @@ class WorldState:
def create_account(
self, balance=0, address=None, concrete_storage=False, dynamic_loader=None
) -> Account:
"""
Create non-contract account
"""Create non-contract account.
:param address: The account's address
:param balance: Initial balance for the account
@ -72,9 +68,9 @@ class WorldState:
return new_account
def create_initialized_contract_account(self, contract_code, storage) -> None:
"""
Creates a new contract account, based on the contract code and storage provided
The contract code only includes the runtime contract bytecode
"""Creates a new contract account, based on the contract code and
storage provided The contract code only includes the runtime contract
bytecode.
:param contract_code: Runtime bytecode for the contract
:param storage: Initial storage for the contract
@ -103,9 +99,9 @@ class WorldState:
return self._annotations
def get_annotations(self, annotation_type: type) -> Iterator[StateAnnotation]:
"""
Filters annotations for the queried annotation type. Designed particularly for
modules with annotations: worldstate.get_annotations(MySpecificModuleAnnotation)
"""Filters annotations for the queried annotation type. Designed
particularly for modules with annotations:
worldstate.get_annotations(MySpecificModuleAnnotation)
:param annotation_type: The type to filter annotations for
:return: filter of matching annotations
@ -113,7 +109,7 @@ class WorldState:
return filter(lambda x: isinstance(x, annotation_type), self.annotations)
def _generate_new_address(self) -> str:
""" Generates a new address for the global state
"""Generates a new address for the global state.
:return:
"""

@ -2,9 +2,7 @@ from abc import ABC, abstractmethod
class BasicSearchStrategy(ABC):
"""
"""
""""""
__slots__ = "work_list", "max_depth"
@ -17,9 +15,7 @@ class BasicSearchStrategy(ABC):
@abstractmethod
def get_strategic_global_state(self):
"""
"""
""""""
raise NotImplementedError("Must be implemented by a subclass")
def __next__(self):

@ -1,6 +1,4 @@
"""
This module implements basic symbolic execution search strategies
"""
"""This module implements basic symbolic execution search strategies."""
from mythril.laser.ethereum.state.global_state import GlobalState
from typing import List
from random import randrange
@ -16,8 +14,8 @@ except ImportError:
from bisect import bisect
def choices(population, weights=None):
"""
Returns a random element out of the population based on weight.
"""Returns a random element out of the population based on weight.
If the relative weights or cumulative weights are not specified,
the selections are made with equal probability.
"""
@ -32,9 +30,9 @@ except ImportError:
class DepthFirstSearchStrategy(BasicSearchStrategy):
"""
Implements a depth first search strategy
I.E. Follow one path to a leaf, and then continue to the next one
"""Implements a depth first search strategy I.E.
Follow one path to a leaf, and then continue to the next one
"""
def get_strategic_global_state(self) -> GlobalState:
@ -46,9 +44,9 @@ class DepthFirstSearchStrategy(BasicSearchStrategy):
class BreadthFirstSearchStrategy(BasicSearchStrategy):
"""
Implements a breadth first search strategy
I.E. Execute all states of a "level" before continuing
"""Implements a breadth first search strategy I.E.
Execute all states of a "level" before continuing
"""
def get_strategic_global_state(self) -> GlobalState:
@ -60,9 +58,7 @@ class BreadthFirstSearchStrategy(BasicSearchStrategy):
class ReturnRandomNaivelyStrategy(BasicSearchStrategy):
"""
chooses a random state from the worklist with equal likelihood
"""
"""chooses a random state from the worklist with equal likelihood."""
def get_strategic_global_state(self) -> GlobalState:
"""
@ -76,9 +72,8 @@ class ReturnRandomNaivelyStrategy(BasicSearchStrategy):
class ReturnWeightedRandomStrategy(BasicSearchStrategy):
"""
chooses a random state from the worklist with likelihood based on inverse proportion to depth
"""
"""chooses a random state from the worklist with likelihood based on
inverse proportion to depth."""
def get_strategic_global_state(self) -> GlobalState:
"""

@ -36,10 +36,12 @@ class SVMError(Exception):
class LaserEVM:
"""The LASER EVM.
Just as Mithril had to be mined at great efforts to provide the Dwarves with their exceptional armour,
LASER stands at the heart of Mythril, digging deep in the depths of call graphs, unearthing the most
precious symbolic call data, that is then hand-forged into beautiful and strong security issues by
the experienced smiths we call detection modules. It is truly a magnificent symbiosis.
Just as Mithril had to be mined at great efforts to provide the
Dwarves with their exceptional armour, LASER stands at the heart of
Mythril, digging deep in the depths of call graphs, unearthing the
most precious symbolic call data, that is then hand-forged into
beautiful and strong security issues by the experienced smiths we
call detection modules. It is truly a magnificent symbiosis.
"""
def __init__(
@ -166,8 +168,9 @@ class LaserEVM:
log.info("Achieved {:.2f}% coverage for code: {}".format(cov, code))
def _execute_transactions(self, address):
"""
This function executes multiple transactions on the address based on the coverage
"""This function executes multiple transactions on the address based on
the coverage.
:param address: Address of the contract
:return:
"""
@ -188,7 +191,8 @@ class LaserEVM:
)
def _get_covered_instructions(self) -> int:
""" Gets the total number of covered instructions for all accounts in the svm
"""Gets the total number of covered instructions for all accounts in
the svm.
:return:
"""

@ -13,20 +13,19 @@ log = logging.getLogger(__name__)
class TaintRecord:
"""
TaintRecord contains tainting information for a specific (state, node)
the information specifies the taint status before executing the operation belonging to the state
"""
"""TaintRecord contains tainting information for a specific (state, node)
the information specifies the taint status before executing the operation
belonging to the state."""
def __init__(self):
""" Builds a taint record """
"""Builds a taint record."""
self.stack = []
self.memory = {}
self.storage = {}
self.states = []
def stack_tainted(self, index: int) -> Union[bool, None]:
""" Returns taint value of stack element at index
"""Returns taint value of stack element at index.
:param index:
:return:
@ -36,7 +35,7 @@ class TaintRecord:
return None
def memory_tainted(self, index: int) -> bool:
""" Returns taint value of memory element at index
"""Returns taint value of memory element at index.
:param index:
:return:
@ -46,7 +45,7 @@ class TaintRecord:
return False
def storage_tainted(self, index: int) -> bool:
""" Returns taint value of storage element at index
"""Returns taint value of storage element at index.
:param index:
:return:
@ -56,14 +55,14 @@ class TaintRecord:
return False
def add_state(self, state: GlobalState) -> None:
""" Adds state with this taint record
"""Adds state with this taint record.
:param state:
"""
self.states.append(state)
def clone(self) -> "TaintRecord":
""" Clones this record
"""Clones this record.
:return:
"""
@ -75,14 +74,15 @@ class TaintRecord:
class TaintResult:
""" Taint analysis result obtained after having ran the taint runner"""
"""Taint analysis result obtained after having ran the taint runner."""
def __init__(self):
"""Create a new tains result."""
self.records = []
def check(self, state: GlobalState, stack_index: int) -> Union[bool, None]:
"""Checks if stack variable is tainted, before executing the instruction
"""Checks if stack variable is tainted, before executing the
instruction.
:param state: state to check variable in
:param stack_index: index of stack variable
@ -94,14 +94,14 @@ class TaintResult:
return record.stack_tainted(stack_index)
def add_records(self, records: List[TaintRecord]) -> None:
""" Adds records to this taint result
"""Adds records to this taint result.
:param records:
"""
self.records += records
def _try_get_record(self, state: GlobalState) -> Union[TaintRecord, None]:
""" Finds record belonging to the state
"""Finds record belonging to the state.
:param state:
:return:
@ -113,16 +113,15 @@ class TaintResult:
class TaintRunner:
"""
Taint runner, is able to run taint analysis on symbolic execution result
"""
"""Taint runner, is able to run taint analysis on symbolic execution
result."""
@staticmethod
def execute(
statespace: SymExecWrapper, node: Node, state: GlobalState, initial_stack=None
) -> TaintResult:
"""
Runs taint analysis on the statespace
"""Runs taint analysis on the statespace.
:param initial_stack:
:param statespace: symbolic statespace to run taint analysis on
:param node: taint introduction node
@ -196,8 +195,8 @@ class TaintRunner:
def execute_node(
node: Node, last_record: TaintRecord, state_index=0
) -> List[TaintRecord]:
"""
Runs taint analysis on a given node
"""Runs taint analysis on a given node.
:param node: node to analyse
:param last_record: last taint record to work from
:param state_index: state index to start from

@ -1,4 +1,5 @@
"""This module contains functions to set up and execute concolic message calls."""
"""This module contains functions to set up and execute concolic message
calls."""
from typing import List, Union
from mythril.disassembler.disassembly import Disassembly
@ -23,7 +24,7 @@ def execute_message_call(
value,
track_gas=False,
) -> Union[None, List[GlobalState]]:
""" Execute a message call transaction from all open states.
"""Execute a message call transaction from all open states.
:param laser_evm:
:param callee_address:
@ -63,7 +64,7 @@ def execute_message_call(
def _setup_global_state_for_execution(laser_evm, transaction) -> None:
""" Set up global state and cfg for a transactions execution.
"""Set up global state and cfg for a transactions execution.
:param laser_evm:
:param transaction:

@ -1,4 +1,5 @@
"""This module contains functions setting up and executing transactions with symbolic values."""
"""This module contains functions setting up and executing transactions with
symbolic values."""
import logging
@ -24,7 +25,7 @@ ATTACKER_ADDRESS = 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
def execute_message_call(laser_evm, callee_address: str) -> None:
""" Executes a message call transaction from all open states
"""Executes a message call transaction from all open states.
:param laser_evm:
:param callee_address:
@ -65,7 +66,7 @@ def execute_message_call(laser_evm, callee_address: str) -> None:
def execute_contract_creation(
laser_evm, contract_initialization_code, contract_name=None
) -> Account:
""" Executes a contract creation transaction from all open states
"""Executes a contract creation transaction from all open states.
:param laser_evm:
:param contract_initialization_code:
@ -110,7 +111,7 @@ def execute_contract_creation(
def _setup_global_state_for_execution(laser_evm, transaction) -> None:
""" Sets up global state and cfg for a transactions execution
"""Sets up global state and cfg for a transactions execution.
:param laser_evm:
:param transaction:

@ -1,4 +1,5 @@
"""This module contians the transaction models used throughout LASER's symbolic execution."""
"""This module contians the transaction models used throughout LASER's symbolic
execution."""
from typing import Union
from mythril.disassembler.disassembly import Disassembly
@ -30,7 +31,7 @@ def get_next_transaction_id() -> int:
class TransactionEndSignal(Exception):
""" Exception raised when a transaction is finalized"""
"""Exception raised when a transaction is finalized."""
def __init__(self, global_state: GlobalState, revert=False):
self.global_state = global_state
@ -38,7 +39,7 @@ class TransactionEndSignal(Exception):
class TransactionStartSignal(Exception):
""" Exception raised when a new transaction is started"""
"""Exception raised when a new transaction is started."""
def __init__(
self,
@ -119,13 +120,13 @@ class BaseTransaction:
class MessageCallTransaction(BaseTransaction):
""" Transaction object models an transaction"""
"""Transaction object models an transaction."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def initial_global_state(self) -> GlobalState:
"""Initialize the execution environment"""
"""Initialize the execution environment."""
environment = Environment(
self.callee_account,
self.caller,
@ -152,7 +153,7 @@ class MessageCallTransaction(BaseTransaction):
class ContractCreationTransaction(BaseTransaction):
""" Transaction object models an transaction"""
"""Transaction object models an transaction."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs, init_call_data=False)
@ -162,7 +163,7 @@ class ContractCreationTransaction(BaseTransaction):
)
def initial_global_state(self) -> GlobalState:
"""Initialize the execution environment"""
"""Initialize the execution environment."""
environment = Environment(
self.callee_account,
self.caller,

@ -1,4 +1,5 @@
"""This module contains various utility conversion functions and constants for LASER."""
"""This module contains various utility conversion functions and constants for
LASER."""
import re
from mythril.laser.smt import is_false, is_true, simplify, If, BitVec, Bool, Expression

@ -23,14 +23,13 @@ import z3
class SymbolFactory:
"""
A symbol factory provides a default interface for all the components of mythril to create symbols
"""
"""A symbol factory provides a default interface for all the components of
mythril to create symbols."""
@staticmethod
def BitVecVal(value: int, size: int, annotations=None):
"""
Creates a new bit vector with a concrete value
"""Creates a new bit vector with a concrete value.
:param value: The concrete value to set the bit vector to
:param size: The size of the bit vector
:param annotations: The annotations to initialize the bit vector with
@ -40,8 +39,8 @@ class SymbolFactory:
@staticmethod
def BitVecSym(name: str, size: int, annotations=None):
"""
Creates a new bit vector with a symbolic value
"""Creates a new bit vector with a symbolic value.
:param name: The name of the symbolic bit vector
:param size: The size of the bit vector
:param annotations: The annotations to initialize the bit vector with
@ -51,38 +50,34 @@ class SymbolFactory:
class _SmtSymbolFactory(SymbolFactory):
"""
An implementation of a SymbolFactory that creates symbols using
the classes in: mythril.laser.smt
"""
"""An implementation of a SymbolFactory that creates symbols using the
classes in: mythril.laser.smt."""
@staticmethod
def BitVecVal(value: int, size: int, annotations=None):
""" Creates a new bit vector with a concrete value """
"""Creates a new bit vector with a concrete value."""
raw = z3.BitVecVal(value, size)
return BitVec(raw, annotations)
@staticmethod
def BitVecSym(name: str, size: int, annotations=None):
""" Creates a new bit vector with a symbolic value """
"""Creates a new bit vector with a symbolic value."""
raw = z3.BitVec(name, size)
return BitVec(raw, annotations)
class _Z3SymbolFactory(SymbolFactory):
"""
An implementation of a SymbolFactory that directly returns
z3 symbols
"""
"""An implementation of a SymbolFactory that directly returns z3
symbols."""
@staticmethod
def BitVecVal(value: int, size: int, annotations=None):
""" Creates a new bit vector with a concrete value """
"""Creates a new bit vector with a concrete value."""
return z3.BitVecVal(value, size)
@staticmethod
def BitVecSym(name: str, size: int, annotations=None):
""" Creates a new bit vector with a symbolic value """
"""Creates a new bit vector with a symbolic value."""
return z3.BitVec(name, size)

@ -1,7 +1,8 @@
"""This module contains an SMT abstraction of arrays.
This includes an Array class to implement basic store and set operations, as well as
as a K-array, which can be initialized with default values over a certain range.
This includes an Array class to implement basic store and set
operations, as well as as a K-array, which can be initialized with
default values over a certain range.
"""
from mythril.laser.smt.bitvec import BitVec
@ -12,7 +13,7 @@ class BaseArray:
"""Base array type, which implements basic store and set operations."""
def __getitem__(self, item: BitVec):
""" Gets item from the array, item can be symbolic"""
"""Gets item from the array, item can be symbolic."""
if isinstance(item, slice):
raise ValueError(
"Instance of BaseArray, does not support getitem with slices"
@ -20,7 +21,7 @@ class BaseArray:
return BitVec(z3.Select(self.raw, item.raw))
def __setitem__(self, key: BitVec, value: BitVec):
""" Sets an item in the array, key can be symbolic"""
"""Sets an item in the array, key can be symbolic."""
self.raw = z3.Store(self.raw, key.raw, value.raw)
@ -28,8 +29,8 @@ class Array(BaseArray):
"""A basic symbolic array."""
def __init__(self, name: str, domain: int, value_range: int):
"""
Initializes a symbolic array
"""Initializes a symbolic array.
:param name: Name of the array
:param domain: The domain for the array (10 -> all the values that a bv of size 10 could take)
:param value_range: The range for the values in the array (10 -> all the values that a bv of size 10 could take)
@ -40,11 +41,12 @@ class Array(BaseArray):
class K(BaseArray):
"""A basic symbolic array, which can be initialized with a default value."""
"""A basic symbolic array, which can be initialized with a default
value."""
def __init__(self, domain: int, value_range: int, value: int):
"""
Initializes an array with a default value
"""Initializes an array with a default value.
:param domain: The domain for the array (10 -> all the values that a bv of size 10 could take)
:param value_range: The range for the values in the array (10 -> all the values that a bv of size 10 could take)
:param value: The default value to use for this array

@ -304,7 +304,8 @@ def BVAddNoOverflow(a: Union[BitVec, int], b: Union[BitVec, int], signed: bool)
def BVMulNoOverflow(a: Union[BitVec, int], b: Union[BitVec, int], signed: bool) -> Bool:
"""Creates predicate that verifies that the multiplication doesn't overflow.
"""Creates predicate that verifies that the multiplication doesn't
overflow.
:param a:
:param b:

@ -1,4 +1,5 @@
"""This module provides classes for an SMT abstraction of boolean expressions."""
"""This module provides classes for an SMT abstraction of boolean
expressions."""
import z3
from typing import Union

@ -4,7 +4,8 @@ import z3
class Expression:
"""This is the base symbol class and maintains functionality for simplification and annotations."""
"""This is the base symbol class and maintains functionality for
simplification and annotations."""
def __init__(self, raw, annotations=None):
"""
@ -17,14 +18,14 @@ class Expression:
@property
def annotations(self):
"""Gets the annotations for this expression
"""Gets the annotations for this expression.
:return:
"""
return self._annotations
def annotate(self, annotation):
"""Annotates this expression with the given annotation
"""Annotates this expression with the given annotation.
:param annotation:
"""

@ -8,20 +8,19 @@ class Solver:
"""An SMT solver object."""
def __init__(self):
"""
"""
""""""
self.raw = z3.Solver()
def set_timeout(self, timeout: int) -> None:
""" Sets the timeout that will be used by this solver, timeout is in milliseconds
"""Sets the timeout that will be used by this solver, timeout is in
milliseconds.
:param timeout:
"""
self.raw.set(timeout=timeout)
def add(self, constraints: list) -> None:
""" Adds the constraints to this solver
"""Adds the constraints to this solver.
:param constraints:
:return:
@ -33,7 +32,7 @@ class Solver:
self.raw.add(constraints)
def append(self, constraints: list) -> None:
""" Adds the constraints to this solver
"""Adds the constraints to this solver.
:param constraints:
:return:
@ -45,14 +44,15 @@ class Solver:
self.raw.add(constraints)
def check(self):
""" Returns z3 smt check result
"""Returns z3 smt check result.
:return:
"""
return self.raw.check()
def model(self):
""" Returns z3 model for a solution
"""Returns z3 model for a solution.
:return:
"""
return self.raw.model()
@ -62,7 +62,7 @@ class Solver:
self.raw.reset()
def pop(self, num) -> None:
""" Pop num constraints from this solver
"""Pop num constraints from this solver.
:param num:
"""
@ -70,9 +70,7 @@ class Solver:
class Optimize(Solver):
"""
An optimizing smt solver
"""
"""An optimizing smt solver."""
def __init__(self):
"""Create a new optimizing solver instance."""
@ -80,14 +78,14 @@ class Optimize(Solver):
self.raw = z3.Optimize()
def minimize(self, element: Expression):
""" In solving this solver will try to minimize the passed expression
"""In solving this solver will try to minimize the passed expression.
:param element:
"""
self.raw.minimize(element.raw)
def maximize(self, element: Expression):
""" In solving this solver will try to maximize the passed expression
"""In solving this solver will try to maximize the passed expression.
:param element:
"""

@ -77,7 +77,6 @@ class Mythril(object):
mythril.dump_statespaces(args)
mythril.disassemble(contract)
mythril.get_state_variable_from_storage(args)
"""
def __init__(
@ -133,8 +132,8 @@ class Mythril(object):
return mythril_dir
def _init_config(self):
"""
If no config file exists, create it and add default options.
"""If no config file exists, create it and add default options.
Default LevelDB path is specified based on OS
dynamic loading is set to infura by default in the file
Returns: leveldb directory

@ -1,4 +1,5 @@
"""This module contains representation classes for Solidity files, contracts and source mappings."""
"""This module contains representation classes for Solidity files, contracts
and source mappings."""
import mythril.laser.ethereum.util as helper
from mythril.ethereum.evmcontract import EVMContract
from mythril.ethereum.util import get_solc_json

@ -1,4 +1,5 @@
"""This module contains the dynamic loader logic to get on-chain storage data and dependencies."""
"""This module contains the dynamic loader logic to get on-chain storage data
and dependencies."""
from mythril.disassembler.disassembly import Disassembly
import logging
import re

@ -75,8 +75,9 @@ except ImportError:
class SQLiteDB(object):
"""
Simple context manager for sqlite3 databases. Commits everything at exit.
"""Simple context manager for sqlite3 databases.
Commits everything at exit.
"""
def __init__(self, path):
@ -112,9 +113,7 @@ class SQLiteDB(object):
class SignatureDB(object, metaclass=Singleton):
"""
"""
""""""
def __init__(self, enable_online_lookup: bool = False, path: str = None) -> None:
"""
@ -146,8 +145,8 @@ class SignatureDB(object, metaclass=Singleton):
)
def __getitem__(self, item: str) -> List[str]:
"""
Provide dict interface db[sighash]
"""Provide dict interface db[sighash]
:param item: 4-byte signature string
:return: list of matching text signature strings
"""
@ -155,8 +154,8 @@ class SignatureDB(object, metaclass=Singleton):
@staticmethod
def _normalize_byte_sig(byte_sig: str) -> str:
"""
Adds a leading 0x to the byte signature if it's not already there.
"""Adds a leading 0x to the byte signature if it's not already there.
:param byte_sig: 4-byte signature string
:return: normalized byte signature string
"""
@ -184,10 +183,9 @@ class SignatureDB(object, metaclass=Singleton):
)
def get(self, byte_sig: str, online_timeout: int = 2) -> List[str]:
"""
Get a function text signature for a byte signature
1) try local cache
2) try online lookup (if enabled; if not flagged as unavailable)
"""Get a function text signature for a byte signature 1) try local
cache 2) try online lookup (if enabled; if not flagged as unavailable)
:param byte_sig: function signature hash as hexstr
:param online_timeout: online lookup timeout
:return: list of matching function text signatures
@ -235,8 +233,8 @@ class SignatureDB(object, metaclass=Singleton):
def import_solidity_file(
self, file_path: str, solc_binary: str = "solc", solc_args: str = None
):
"""
Import Function Signatures from solidity source files
"""Import Function Signatures from solidity source files.
:param solc_binary:
:param solc_args:
:param file_path: solidity source code file path
@ -283,8 +281,7 @@ class SignatureDB(object, metaclass=Singleton):
@staticmethod
def lookup_online(byte_sig: str, timeout: int, proxies=None) -> List[str]:
"""
Lookup function signatures from 4byte.directory.
"""Lookup function signatures from 4byte.directory.
:param byte_sig: function signature hash as hexstr
:param timeout: optional timeout for online lookup

@ -1,4 +1,5 @@
"""This module contains functionality used to easily analyse Truffle projects."""
"""This module contains functionality used to easily analyse Truffle
projects."""
import os
from pathlib import PurePath
import re

@ -1,6 +1,7 @@
"""This file contains the current Mythril version.
This file is suitable for sourcing inside POSIX shell, e.g. bash as well as for importing into Python.
This file is suitable for sourcing inside POSIX shell, e.g. bash as well
as for importing into Python.
"""
VERSION = "v0.19.11" # NOQA

@ -1,13 +1,11 @@
# -*- coding: utf-8 -*-
"""
install mythril and deploy source-dist and wheel to pypi.python.org
"""install mythril and deploy source-dist and wheel to pypi.python.org.
deps (requires up2date version):
*) pip install --upgrade pip wheel setuptools twine
publish to pypi w/o having to convert Readme.md to RST:
1) #> python setup.py sdist bdist_wheel
2) #> twine upload dist/* #<specify bdist_wheel version to upload>; #optional --repository <testpypi> or --repository-url <testpypi-url>
"""
from setuptools import setup, find_packages
from setuptools.command.install import install
@ -27,14 +25,12 @@ exec(open(str(version_path), "r").read())
class VerifyVersionCommand(install):
"""Custom command to verify that the git tag matches our version"""
"""Custom command to verify that the git tag matches our version."""
description = "verify that the git tag matches our version"
def run(self):
"""
"""
""""""
tag = os.getenv("CIRCLE_TAG")
if tag != VERSION:
@ -45,8 +41,8 @@ class VerifyVersionCommand(install):
def read_file(fname):
"""
return file contents
"""return file contents.
:param fname: path relative to setup.py
:return: file contents
"""

@ -17,9 +17,7 @@ MYTHRIL_DIR = TESTS_DIR / "mythril_dir"
class BaseTestCase(TestCase):
def setUp(self):
"""
"""
""""""
self.changed_files = []
def compare_files_error_message(self):
@ -46,9 +44,7 @@ class BaseTestCase(TestCase):
self.changed_files.append((input_file, output_expected, output_current))
def assert_and_show_changed_files(self):
"""
"""
""""""
self.assertEqual(
0, len(self.changed_files), msg=self.compare_files_error_message()
)

@ -4,9 +4,7 @@ from tests import BaseTestCase
class EVMContractTestCase(BaseTestCase):
def setUp(self):
"""
"""
""""""
super().setUp()
self.code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029"
self.creation_code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029"
@ -14,9 +12,7 @@ class EVMContractTestCase(BaseTestCase):
class Getinstruction_listTestCase(EVMContractTestCase):
def runTest(self):
"""
"""
""""""
contract = EVMContract(self.code, self.creation_code)
disassembly = contract.disassembly
@ -30,9 +26,7 @@ class Getinstruction_listTestCase(EVMContractTestCase):
class GetEASMTestCase(EVMContractTestCase):
def runTest(self):
"""
"""
""""""
contract = EVMContract(self.code)
instruction_list = contract.get_easm()
@ -45,9 +39,7 @@ class GetEASMTestCase(EVMContractTestCase):
class MatchesExpressionTestCase(EVMContractTestCase):
def runTest(self):
"""
"""
""""""
contract = EVMContract(self.code)
self.assertTrue(

@ -87,9 +87,7 @@ def _test_natives(laser_info, test_list, test_name):
class NativeTests(BaseTestCase):
@staticmethod
def runTest():
"""
"""
""""""
disassembly = SolidityContract(
"./tests/native_tests.sol", solc_binary=Mythril._init_solc_binary("0.5.0")
).disassembly

@ -41,7 +41,7 @@ def _generate_report(input_file):
@pytest.fixture(scope="module")
def reports():
""" Fixture that analyses all reports"""
"""Fixture that analyses all reports."""
reset_callback_modules()
pool = Pool(cpu_count())
input_files = sorted(
@ -53,7 +53,8 @@ def reports():
def _assert_empty(changed_files, postfix):
""" Asserts there are no changed files and otherwise builds error message"""
"""Asserts there are no changed files and otherwise builds error
message."""
message = ""
for input_file in changed_files:
output_expected = (
@ -76,7 +77,8 @@ def _assert_empty(changed_files, postfix):
def _assert_empty_json(changed_files):
""" Asserts there are no changed files and otherwise builds error message"""
"""Asserts there are no changed files and otherwise builds error
message."""
postfix = ".json"
expected = []
actual = []
@ -111,8 +113,8 @@ def _assert_empty_json(changed_files):
def _get_changed_files(postfix, report_builder, reports):
"""
Returns a generator for all unexpected changes in generated reports
"""Returns a generator for all unexpected changes in generated reports.
:param postfix: The applicable postfix
:param report_builder: serialization function
:param reports: The reports to serialize

@ -8,15 +8,11 @@ class RpcTest(BaseTestCase):
client = None
def setUp(self):
"""
"""
""""""
self.client = EthJsonRpc()
def tearDown(self):
"""
"""
""""""
self.client.close()
def test_eth_coinbase(self):

Loading…
Cancel
Save