Merge branch 'refactor/cli' of github.com:ConsenSys/mythril into refactor/cli

pull/1033/head
Nikhil Parasaram 6 years ago
commit 40bd45b271
  1. 14
      .circleci/config.yml
  2. 12
      Dockerfile
  3. 23
      mythril/analysis/callgraph.py
  4. 21
      mythril/analysis/modules/external_calls.py
  5. 53
      mythril/analysis/symbolic.py
  6. 20
      mythril/laser/ethereum/call.py
  7. 28
      mythril/laser/ethereum/instructions.py
  8. 46
      mythril/laser/ethereum/state/account.py
  9. 2
      mythril/laser/ethereum/state/environment.py
  10. 2
      mythril/laser/ethereum/state/global_state.py
  11. 57
      mythril/laser/ethereum/state/world_state.py
  12. 89
      mythril/laser/ethereum/svm.py
  13. 31
      mythril/laser/ethereum/transaction/symbolic.py
  14. 16
      mythril/laser/ethereum/transaction/transaction_models.py
  15. 7
      mythril/laser/smt/bool.py
  16. 22
      mythril/solidity/soliditycontract.py
  17. 2
      mythril/version.py
  18. 23
      tests/laser/evm_testsuite/evm_test.py
  19. 12
      tests/laser/test_transaction.py
  20. 6
      tests/laser/transaction/symbolic_test.py
  21. 19
      tests/native_test.py
  22. 2
      tests/report_test.py
  23. 36
      tests/testdata/outputs_expected/environments.sol.o.json
  24. 34
      tests/testdata/outputs_expected/environments.sol.o.markdown
  25. 30
      tests/testdata/outputs_expected/environments.sol.o.text
  26. 12
      tests/testdata/outputs_expected/ether_send.sol.o.jsonv2
  27. 12
      tests/testdata/outputs_expected/metacoin.sol.o.jsonv2
  28. 12
      tests/testdata/outputs_expected/nonascii.sol.o.jsonv2
  29. 13
      tests/testdata/outputs_expected/overflow.sol.o.json
  30. 17
      tests/testdata/outputs_expected/overflow.sol.o.jsonv2
  31. 13
      tests/testdata/outputs_expected/overflow.sol.o.markdown
  32. 11
      tests/testdata/outputs_expected/overflow.sol.o.text
  33. 166
      tests/testdata/outputs_expected/rubixi.sol.o.json
  34. 238
      tests/testdata/outputs_expected/rubixi.sol.o.markdown
  35. 177
      tests/testdata/outputs_expected/rubixi.sol.o.text
  36. 13
      tests/testdata/outputs_expected/underflow.sol.o.json
  37. 17
      tests/testdata/outputs_expected/underflow.sol.o.jsonv2
  38. 13
      tests/testdata/outputs_expected/underflow.sol.o.markdown
  39. 11
      tests/testdata/outputs_expected/underflow.sol.o.text
  40. 46
      tests/testdata/outputs_expected/weak_random.sol.o.json
  41. 62
      tests/testdata/outputs_expected/weak_random.sol.o.markdown
  42. 46
      tests/testdata/outputs_expected/weak_random.sol.o.text

@ -108,12 +108,14 @@ jobs:
command: sleep 15s command: sleep 15s
- run: - run:
name: Quick Edelweiss test name: Quick Edelweiss test
command: /home/run-edelweiss-test.sh CircleCI/latest.quick.csv command: /home/run-edelweiss-test.sh CircleCI/latest.quick.csv 5
- run:
name: Full Edelweiss test # TODO: Temporary disabled
environment: # - run:
MYTHX_API_FULL_MODE: true # name: Full Edelweiss test
command: /home/run-edelweiss-test.sh CircleCI/latest.full.csv # environment:
# MYTHX_API_FULL_MODE: true
# command: /home/run-edelweiss-test.sh CircleCI/latest.full.csv
pypi_release: pypi_release:
<<: *defaults <<: *defaults

@ -1,5 +1,8 @@
FROM ubuntu:bionic FROM ubuntu:bionic
# Space-separated version string without leading 'v' (e.g. "0.4.21 0.4.22")
ARG SOLC
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y \ && apt-get install -y \
libsqlite3-0 \ libsqlite3-0 \
@ -36,5 +39,12 @@ COPY . /opt/mythril
RUN cd /opt/mythril \ RUN cd /opt/mythril \
&& python setup.py install && python setup.py install
COPY ./mythril/support/assets/signatures.db /root/.mythril/signatures.db RUN useradd -m mythril
USER mythril
WORKDIR /home/mythril
RUN ( [ ! -z "${SOLC}" ] && set -e && for ver in $SOLC; do python -m solc.install v${ver}; done ) || true
COPY ./mythril/support/assets/signatures.db /home/mythril/.mythril/signatures.db
ENTRYPOINT ["/usr/local/bin/myth"] ENTRYPOINT ["/usr/local/bin/myth"]

@ -125,7 +125,7 @@ phrack_color = {
} }
def extract_nodes(statespace, color_map): def extract_nodes(statespace):
""" """
:param statespace: :param statespace:
@ -133,6 +133,7 @@ def extract_nodes(statespace, color_map):
:return: :return:
""" """
nodes = [] nodes = []
color_map = {}
for node_key in statespace.nodes: for node_key in statespace.nodes:
node = statespace.nodes[node_key] node = statespace.nodes[node_key]
instructions = [state.get_current_instruction() for state in node.states] instructions = [state.get_current_instruction() for state in node.states]
@ -164,10 +165,16 @@ def extract_nodes(statespace, color_map):
else "\n".join(code_split[:6]) + "\n(click to expand +)" else "\n".join(code_split[:6]) + "\n(click to expand +)"
) )
if node.get_cfg_dict()["contract_name"] not in color_map.keys():
color = default_colors[len(color_map) % len(default_colors)]
color_map[node.get_cfg_dict()["contract_name"]] = color
nodes.append( nodes.append(
{ {
"id": str(node_key), "id": str(node_key),
"color": color_map[node.get_cfg_dict()["contract_name"]], "color": color_map.get(
node.get_cfg_dict()["contract_name"], default_colors[0]
),
"size": 150, "size": 150,
"fullLabel": "\n".join(code_split), "fullLabel": "\n".join(code_split),
"label": truncated_code, "label": truncated_code,
@ -231,22 +238,12 @@ def generate_graph(
template = env.get_template("callgraph.html") template = env.get_template("callgraph.html")
graph_opts = default_opts graph_opts = default_opts
accounts = statespace.accounts
if phrackify:
color_map = {accounts[k].contract_name: phrack_color for k in accounts}
graph_opts.update(phrack_opts)
else:
color_map = {
accounts[k].contract_name: default_colors[i % len(default_colors)]
for i, k in enumerate(accounts)
}
graph_opts["physics"]["enabled"] = physics graph_opts["physics"]["enabled"] = physics
return template.render( return template.render(
title=title, title=title,
nodes=extract_nodes(statespace, color_map), nodes=extract_nodes(statespace),
edges=extract_edges(statespace), edges=extract_edges(statespace),
phrackify=phrackify, phrackify=phrackify,
opts=graph_opts, opts=graph_opts,

@ -5,7 +5,7 @@ from mythril.analysis import solver
from mythril.analysis.swc_data import REENTRANCY from mythril.analysis.swc_data import REENTRANCY
from mythril.analysis.modules.base import DetectionModule from mythril.analysis.modules.base import DetectionModule
from mythril.analysis.report import Issue from mythril.analysis.report import Issue
from mythril.laser.smt import UGT, symbol_factory from mythril.laser.smt import UGT, symbol_factory, Or, BitVec
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.exceptions import UnsatError from mythril.exceptions import UnsatError
from copy import copy from copy import copy
@ -71,6 +71,8 @@ def _analyze_state(state):
) )
except UnsatError: except UnsatError:
if _is_precompile_call(state):
return []
log.debug( log.debug(
"[EXTERNAL_CALLS] Callee address cannot be modified. Reporting informational issue." "[EXTERNAL_CALLS] Callee address cannot be modified. Reporting informational issue."
@ -104,6 +106,23 @@ def _analyze_state(state):
return [issue] return [issue]
def _is_precompile_call(global_state: GlobalState):
to = global_state.mstate.stack[-2] # type: BitVec
constraints = copy(global_state.mstate.constraints)
constraints += [
Or(
to < symbol_factory.BitVecVal(1, 256),
to > symbol_factory.BitVecVal(16, 256),
)
]
try:
solver.get_model(constraints)
return False
except UnsatError:
return True
class ExternalCalls(DetectionModule): class ExternalCalls(DetectionModule):
"""This module searches for low level calls (e.g. call.value()) that """This module searches for low level calls (e.g. call.value()) that
forward all gas to the callee.""" forward all gas to the callee."""

@ -2,22 +2,22 @@
purposes.""" purposes."""
import copy import copy
from ethereum.utils import mk_contract_address
from mythril.analysis.security import get_detection_module_hooks, get_detection_modules from mythril.analysis.security import get_detection_module_hooks, get_detection_modules
from mythril.laser.ethereum import svm from mythril.laser.ethereum import svm
from mythril.laser.ethereum.plugins.plugin_factory import PluginFactory
from mythril.laser.ethereum.plugins.plugin_loader import LaserPluginLoader
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.world_state import WorldState
from mythril.laser.ethereum.strategy.basic import ( from mythril.laser.ethereum.strategy.basic import (
BreadthFirstSearchStrategy, BreadthFirstSearchStrategy,
DepthFirstSearchStrategy, DepthFirstSearchStrategy,
ReturnRandomNaivelyStrategy, ReturnRandomNaivelyStrategy,
ReturnWeightedRandomStrategy, ReturnWeightedRandomStrategy,
BasicSearchStrategy,
) )
from mythril.laser.ethereum.transaction.symbolic import CREATOR_ADDRESS from mythril.laser.smt import symbol_factory, BitVec
from typing import Union, List, Dict, Type
from mythril.laser.ethereum.plugins.plugin_factory import PluginFactory
from mythril.laser.ethereum.plugins.plugin_loader import LaserPluginLoader
from mythril.solidity.soliditycontract import EVMContract, SolidityContract from mythril.solidity.soliditycontract import EVMContract, SolidityContract
from .ops import Call, SStore, VarType, get_variable from .ops import Call, SStore, VarType, get_variable
@ -32,7 +32,7 @@ class SymExecWrapper:
def __init__( def __init__(
self, self,
contract, contract,
address, address: Union[int, str, BitVec],
strategy, strategy,
dynloader=None, dynloader=None,
max_depth=22, max_depth=22,
@ -55,8 +55,13 @@ class SymExecWrapper:
:param transaction_count: :param transaction_count:
:param modules: :param modules:
""" """
if isinstance(address, str):
address = symbol_factory.BitVecVal(int(address, 16), 256)
if isinstance(address, int):
address = symbol_factory.BitVecVal(address, 256)
if strategy == "dfs": if strategy == "dfs":
s_strategy = DepthFirstSearchStrategy s_strategy = DepthFirstSearchStrategy # type: Type[BasicSearchStrategy]
elif strategy == "bfs": elif strategy == "bfs":
s_strategy = BreadthFirstSearchStrategy s_strategy = BreadthFirstSearchStrategy
elif strategy == "naive-random": elif strategy == "naive-random":
@ -66,19 +71,11 @@ class SymExecWrapper:
else: else:
raise ValueError("Invalid strategy argument supplied") raise ValueError("Invalid strategy argument supplied")
account = Account(
address,
contract.disassembly,
dynamic_loader=dynloader,
contract_name=contract.name,
)
requires_statespace = ( requires_statespace = (
compulsory_statespace or len(get_detection_modules("post", modules)) > 0 compulsory_statespace or len(get_detection_modules("post", modules)) > 0
) )
self.accounts = {address: account}
self.laser = svm.LaserEVM( self.laser = svm.LaserEVM(
self.accounts,
dynamic_loader=dynloader, dynamic_loader=dynloader,
max_depth=max_depth, max_depth=max_depth,
execution_timeout=execution_timeout, execution_timeout=execution_timeout,
@ -111,12 +108,16 @@ class SymExecWrapper:
creation_code=contract.creation_code, contract_name=contract.name creation_code=contract.creation_code, contract_name=contract.name
) )
else: else:
self.laser.sym_exec(address) account = Account(
created_address = "0x" + str(mk_contract_address(CREATOR_ADDRESS, 0).hex()) address,
for key, value in self.laser.world_state.accounts.items(): contract.disassembly,
if created_address == value.address: dynamic_loader=dynloader,
contract.code = value.code.bytecode contract_name=contract.name,
break concrete_storage=False,
)
world_state = WorldState()
world_state.put_account(account)
self.laser.sym_exec(world_state=world_state, target_address=address.value)
if not requires_statespace: if not requires_statespace:
return return
@ -126,8 +127,8 @@ class SymExecWrapper:
# Generate lists of interesting operations # Generate lists of interesting operations
self.calls = [] self.calls = [] # type: List[Call]
self.sstors = {} self.sstors = {} # type: Dict[int, Dict[str, List[SStore]]]
for key in self.nodes: for key in self.nodes:
@ -204,7 +205,7 @@ class SymExecWrapper:
elif op == "SSTORE": elif op == "SSTORE":
stack = copy.copy(state.mstate.stack) stack = copy.copy(state.mstate.stack)
address = state.environment.active_account.address address = state.environment.active_account.address.value
index, value = stack.pop(), stack.pop() index, value = stack.pop(), stack.pop()

@ -3,13 +3,12 @@ instructions.py to get the necessary elements from the stack and determine the
parameters for the new global state.""" parameters for the new global state."""
import logging import logging
import re
from typing import Union, List, cast, Callable from typing import Union, List, cast, Callable
from z3 import Z3Exception
from mythril.laser.smt import BitVec import mythril.laser.ethereum.util as util
from mythril.laser.ethereum import natives from mythril.laser.ethereum import natives
from mythril.laser.ethereum.gas import OPCODE_GAS from mythril.laser.ethereum.gas import OPCODE_GAS
from mythril.laser.smt import simplify, Expression, symbol_factory
import mythril.laser.ethereum.util as util
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.calldata import ( from mythril.laser.ethereum.state.calldata import (
BaseCalldata, BaseCalldata,
@ -17,8 +16,9 @@ from mythril.laser.ethereum.state.calldata import (
ConcreteCalldata, ConcreteCalldata,
) )
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.smt import BitVec
from mythril.laser.smt import simplify, Expression, symbol_factory
from mythril.support.loader import DynLoader from mythril.support.loader import DynLoader
import re
""" """
This module contains the business logic used by Instruction in instructions.py This module contains the business logic used by Instruction in instructions.py
@ -96,7 +96,7 @@ def get_callee_address(
# attempt to read the contract address from instance storage # attempt to read the contract address from instance storage
try: try:
callee_address = dynamic_loader.read_storage( callee_address = dynamic_loader.read_storage(
environment.active_account.address, index str(hex(environment.active_account.address.value)), index
) )
# TODO: verify whether this happens or not # TODO: verify whether this happens or not
except: except:
@ -124,7 +124,7 @@ def get_callee_account(
accounts = global_state.accounts accounts = global_state.accounts
try: try:
return global_state.accounts[callee_address] return global_state.accounts[int(callee_address, 16)]
except KeyError: except KeyError:
# We have a valid call address, but contract is not in the modules list # We have a valid call address, but contract is not in the modules list
log.debug("Module with address " + callee_address + " not loaded.") log.debug("Module with address " + callee_address + " not loaded.")
@ -145,7 +145,11 @@ def get_callee_account(
log.debug("Dependency loaded: " + callee_address) log.debug("Dependency loaded: " + callee_address)
callee_account = Account( callee_account = Account(
callee_address, code, callee_address, dynamic_loader=dynamic_loader symbol_factory.BitVecVal(int(callee_address, 16), 256),
code,
callee_address,
dynamic_loader=dynamic_loader,
balances=global_state.world_state.balances,
) )
accounts[callee_address] = callee_account accounts[callee_address] = callee_account

@ -1520,7 +1520,7 @@ class Instruction:
global_state.environment.active_account global_state.environment.active_account
) )
global_state.accounts[ global_state.accounts[
global_state.environment.active_account.address global_state.environment.active_account.address.value
] = global_state.environment.active_account ] = global_state.environment.active_account
global_state.environment.active_account.storage[index] = ( global_state.environment.active_account.storage[index] = (
@ -1756,31 +1756,19 @@ class Instruction:
:param global_state: :param global_state:
""" """
target = global_state.mstate.stack.pop() target = global_state.mstate.stack.pop()
account_created = False transfer_amount = global_state.environment.active_account.balance()
# Often the target of the suicide instruction will be symbolic # Often the target of the suicide instruction will be symbolic
# If it isn't then well transfer the balance to the indicated contract # If it isn't then we'll transfer the balance to the indicated contract
if isinstance(target, BitVec) and not target.symbolic: global_state.world_state[target].add_balance(transfer_amount)
target = "0x" + hex(target.value)[-40:]
if isinstance(target, str):
try:
global_state.world_state[
target
].balance += global_state.environment.active_account.balance
except KeyError:
global_state.world_state.create_account(
address=target,
balance=global_state.environment.active_account.balance,
)
account_created = True
global_state.environment.active_account = deepcopy( global_state.environment.active_account = deepcopy(
global_state.environment.active_account global_state.environment.active_account
) )
global_state.accounts[ global_state.accounts[
global_state.environment.active_account.address global_state.environment.active_account.address.value
] = global_state.environment.active_account ] = global_state.environment.active_account
global_state.environment.active_account.balance = 0 global_state.environment.active_account.set_balance(0)
global_state.environment.active_account.deleted = True global_state.environment.active_account.deleted = True
global_state.current_transaction.end(global_state) global_state.current_transaction.end(global_state)
@ -1865,9 +1853,7 @@ class Instruction:
gas_price=environment.gasprice, gas_price=environment.gasprice,
gas_limit=gas, gas_limit=gas,
origin=environment.origin, origin=environment.origin,
caller=symbol_factory.BitVecVal( caller=environment.active_account.address,
int(environment.active_account.address, 16), 256
),
callee_account=callee_account, callee_account=callee_account,
call_data=call_data, call_data=call_data,
call_value=value, call_value=value,

@ -7,6 +7,7 @@ from typing import Any, Dict, KeysView, Union
from z3 import ExprRef from z3 import ExprRef
from mythril.laser.smt import Array, symbol_factory, BitVec
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from mythril.laser.smt import symbol_factory from mythril.laser.smt import symbol_factory
@ -30,7 +31,7 @@ class Storage:
except KeyError: except KeyError:
if ( if (
self.address self.address
and int(self.address[2:], 16) != 0 and self.address.value != 0
and (self.dynld and self.dynld.storage_loading) and (self.dynld and self.dynld.storage_loading)
): ):
try: try:
@ -74,10 +75,10 @@ class Account:
def __init__( def __init__(
self, self,
address: str, address: Union[BitVec, str],
code=None, code=None,
contract_name="unknown", contract_name="unknown",
balance=None, balances: Array = None,
concrete_storage=False, concrete_storage=False,
dynamic_loader=None, dynamic_loader=None,
) -> None: ) -> None:
@ -91,36 +92,51 @@ class Account:
""" """
self.nonce = 0 self.nonce = 0
self.code = code or Disassembly("") self.code = code or Disassembly("")
self.balance = ( self.address = (
balance address
if balance if isinstance(address, BitVec)
else symbol_factory.BitVecSym("{}_balance".format(address), 256) else symbol_factory.BitVecVal(int(address, 16), 256)
) )
self.storage = Storage( self.storage = Storage(
concrete_storage, address=address, dynamic_loader=dynamic_loader concrete_storage, address=self.address, dynamic_loader=dynamic_loader
) )
# Metadata # Metadata
self.address = address
self.contract_name = contract_name self.contract_name = contract_name
self.deleted = False self.deleted = False
self._balances = balances
self.balance = lambda: self._balances[self.address]
def __str__(self) -> str: def __str__(self) -> str:
return str(self.as_dict) return str(self.as_dict)
def set_balance(self, balance: ExprRef) -> None: def set_balance(self, balance: Union[int, BitVec]) -> None:
""" """
:param balance: :param balance:
""" """
self.balance = balance balance = (
symbol_factory.BitVecVal(balance, 256)
if isinstance(balance, int)
else balance
)
assert self._balances is not None
self._balances[self.address] = balance
def add_balance(self, balance: ExprRef) -> None: def add_balance(self, balance: Union[int, BitVec]) -> None:
""" """
:param balance: :param balance:
""" """
self.balance += balance balance = (
symbol_factory.BitVecVal(balance, 256)
if isinstance(balance, int)
else balance
)
self._balances[self.address] += balance
@property @property
def as_dict(self) -> Dict: def as_dict(self) -> Dict:
@ -131,7 +147,7 @@ class Account:
return { return {
"nonce": self.nonce, "nonce": self.nonce,
"code": self.code, "code": self.code,
"balance": self.balance, "balance": self.balance(),
"storage": self.storage, "storage": self.storage,
} }
@ -139,8 +155,8 @@ class Account:
new_account = Account( new_account = Account(
address=self.address, address=self.address,
code=self.code, code=self.code,
balance=self.balance,
contract_name=self.contract_name, contract_name=self.contract_name,
balances=self._balances,
) )
new_account.storage = deepcopy(self.storage) new_account.storage = deepcopy(self.storage)
new_account.code = self.code new_account.code = self.code

@ -39,7 +39,7 @@ class Environment:
self.active_account = active_account self.active_account = active_account
self.active_function_name = "" self.active_function_name = ""
self.address = symbol_factory.BitVecVal(int(active_account.address, 16), 256) self.address = active_account.address
# Ib # Ib
self.code = active_account.code if code is None else code self.code = active_account.code if code is None else code

@ -77,7 +77,7 @@ class GlobalState:
:return: :return:
""" """
return self.world_state.accounts return self.world_state._accounts
# TODO: remove this, as two instructions are confusing # TODO: remove this, as two instructions are confusing
def get_current_instruction(self) -> Dict: def get_current_instruction(self) -> Dict:

@ -2,6 +2,8 @@
from copy import copy from copy import copy
from random import randint from random import randint
from typing import Dict, List, Iterator, Optional, TYPE_CHECKING from typing import Dict, List, Iterator, Optional, TYPE_CHECKING
from mythril.laser.smt import symbol_factory, Array, BitVec
from ethereum.utils import mk_contract_address from ethereum.utils import mk_contract_address
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.annotation import StateAnnotation from mythril.laser.ethereum.state.annotation import StateAnnotation
@ -22,18 +24,29 @@ class WorldState:
:param transaction_sequence: :param transaction_sequence:
:param annotations: :param annotations:
""" """
self.accounts = {} # type: Dict[str, Account] self._accounts = {} # type: Dict[int, Account]
self.balances = Array("balance", 256, 256)
self.node = None # type: Optional['Node'] self.node = None # type: Optional['Node']
self.transaction_sequence = transaction_sequence or [] self.transaction_sequence = transaction_sequence or []
self._annotations = annotations or [] self._annotations = annotations or []
def __getitem__(self, item: str) -> Account: @property
def accounts(self):
return self._accounts
def __getitem__(self, item: BitVec) -> 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 :param item: Address of the account to get
:return: Account associated with the address :return: Account associated with the address
""" """
return self.accounts[item] try:
return self._accounts[item.value]
except KeyError:
new_account = Account(address=item, code=None, balances=self.balances)
self._accounts[item.value] = new_account
return new_account
def __copy__(self) -> "WorldState": def __copy__(self) -> "WorldState":
""" """
@ -45,7 +58,9 @@ class WorldState:
transaction_sequence=self.transaction_sequence[:], transaction_sequence=self.transaction_sequence[:],
annotations=new_annotations, annotations=new_annotations,
) )
new_world_state.accounts = copy(self.accounts) new_world_state.balances = copy(self.balances)
for account in self._accounts.values():
new_world_state.put_account(copy(account))
new_world_state.node = self.node new_world_state.node = self.node
return new_world_state return new_world_state
@ -65,14 +80,22 @@ class WorldState:
:param dynamic_loader: used for dynamically loading storage from the block chain :param dynamic_loader: used for dynamically loading storage from the block chain
:return: The new account :return: The new account
""" """
address = address if address else self._generate_new_address(creator) address = (
symbol_factory.BitVecVal(address, 256)
if address
else self._generate_new_address(creator)
)
new_account = Account( new_account = Account(
address, address=address,
balance=balance, balances=self.balances,
dynamic_loader=dynamic_loader, dynamic_loader=dynamic_loader,
concrete_storage=concrete_storage, concrete_storage=concrete_storage,
) )
self._put_account(new_account) if balance:
new_account.set_balance(symbol_factory.BitVecVal(balance, 256))
self.put_account(new_account)
return new_account return new_account
def create_initialized_contract_account(self, contract_code, storage) -> None: def create_initialized_contract_account(self, contract_code, storage) -> None:
@ -86,10 +109,10 @@ class WorldState:
""" """
# TODO: Add type hints # TODO: Add type hints
new_account = Account( new_account = Account(
self._generate_new_address(), code=contract_code, balance=0 self._generate_new_address(), code=contract_code, balances=self.balances
) )
new_account.storage = storage new_account.storage = storage
self._put_account(new_account) self.put_account(new_account)
def annotate(self, annotation: StateAnnotation) -> None: def annotate(self, annotation: StateAnnotation) -> None:
""" """
@ -116,22 +139,24 @@ class WorldState:
""" """
return filter(lambda x: isinstance(x, annotation_type), self.annotations) return filter(lambda x: isinstance(x, annotation_type), self.annotations)
def _generate_new_address(self, creator=None) -> str: def _generate_new_address(self, creator=None) -> BitVec:
"""Generates a new address for the global state. """Generates a new address for the global state.
:return: :return:
""" """
if creator: if creator:
# TODO: Use nounce # TODO: Use nounce
return "0x" + str(mk_contract_address(creator, 0).hex()) address = "0x" + str(mk_contract_address(creator, 0).hex())
return symbol_factory.BitVecVal(int(address, 16), 256)
while True: while True:
address = "0x" + "".join([str(hex(randint(0, 16)))[-1] for _ in range(40)]) address = "0x" + "".join([str(hex(randint(0, 16)))[-1] for _ in range(40)])
if address not in self.accounts.keys(): if address not in self._accounts.keys():
return address return symbol_factory.BitVecVal(int(address, 16), 256)
def _put_account(self, account: Account) -> None: def put_account(self, account: Account) -> None:
""" """
:param account: :param account:
""" """
self.accounts[account.address] = account self._accounts[account.address.value] = account
account._balances = self.balances

@ -9,12 +9,12 @@ from mythril.laser.ethereum.cfg import NodeFlags, Node, Edge, JumpType
from mythril.laser.ethereum.evm_exceptions import StackUnderflowException from mythril.laser.ethereum.evm_exceptions import StackUnderflowException
from mythril.laser.ethereum.evm_exceptions import VmException from mythril.laser.ethereum.evm_exceptions import VmException
from mythril.laser.ethereum.instructions import Instruction from mythril.laser.ethereum.instructions import Instruction
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.iprof import InstructionProfiler
from mythril.laser.ethereum.plugins.signals import PluginSkipWorldState
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum.state.world_state import WorldState from mythril.laser.ethereum.state.world_state import WorldState
from mythril.laser.ethereum.strategy.basic import DepthFirstSearchStrategy from mythril.laser.ethereum.strategy.basic import DepthFirstSearchStrategy
from mythril.laser.ethereum.time_handler import time_handler from mythril.laser.ethereum.time_handler import time_handler
from mythril.laser.ethereum.plugins.signals import PluginSkipWorldState
from mythril.laser.ethereum.transaction import ( from mythril.laser.ethereum.transaction import (
ContractCreationTransaction, ContractCreationTransaction,
TransactionEndSignal, TransactionEndSignal,
@ -22,7 +22,7 @@ from mythril.laser.ethereum.transaction import (
execute_contract_creation, execute_contract_creation,
execute_message_call, execute_message_call,
) )
from mythril.laser.ethereum.iprof import InstructionProfiler from mythril.laser.smt import symbol_factory
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -46,7 +46,6 @@ class LaserEVM:
def __init__( def __init__(
self, self,
accounts: Dict[str, Account],
dynamic_loader=None, dynamic_loader=None,
max_depth=float("inf"), max_depth=float("inf"),
execution_timeout=60, execution_timeout=60,
@ -57,21 +56,18 @@ class LaserEVM:
enable_iprof=False, enable_iprof=False,
) -> None: ) -> None:
""" """
Initializes the laser evm object
:param accounts: :param dynamic_loader: Loads data from chain
:param dynamic_loader: :param max_depth: Maximum execution depth this vm should execute
:param max_depth: :param execution_timeout: Time to take for execution
:param execution_timeout: :param create_timeout: Time to take for contract creation
:param create_timeout: :param strategy: Execution search strategy
:param strategy: :param transaction_count: The amount of transactions to execute
:param transaction_count: :param requires_statespace: Variable indicating whether the statespace should be recorded
:param enable_iprof: Variable indicating whether instruction profiling should be turned on
""" """
world_state = WorldState() self.open_states = [] # type: List[WorldState]
world_state.accounts = accounts
# this sets the initial world state
self.world_state = world_state
self.open_states = [world_state]
self.total_states = 0 self.total_states = 0
self.dynamic_loader = dynamic_loader self.dynamic_loader = dynamic_loader
@ -106,23 +102,30 @@ class LaserEVM:
log.info("LASER EVM initialized with dynamic loader: " + str(dynamic_loader)) log.info("LASER EVM initialized with dynamic loader: " + str(dynamic_loader))
@property
def accounts(self) -> Dict[str, Account]:
"""
:return:
"""
return self.world_state.accounts
def sym_exec( def sym_exec(
self, main_address=None, creation_code=None, contract_name=None self,
world_state: WorldState = None,
target_address: int = None,
creation_code: str = None,
contract_name: str = None,
) -> None: ) -> None:
""" """ Starts symbolic execution
There are two modes of execution.
Either we analyze a preconfigured configuration, in which case the world_state and target_address variables
must be supplied.
Or we execute the creation code of a contract, in which case the creation code and desired name of that
contract should be provided.
:param world_state The world state configuration from which to perform analysis
:param target_address The address of the contract account in the world state which analysis should target
:param creation_code The creation code to create the target contract in the symbolic environment
:param contract_name The name that the created account should be associated with
"""
pre_configuration_mode = world_state is not None and target_address is not None
scratch_mode = creation_code is not None and contract_name is not None
if pre_configuration_mode == scratch_mode:
raise ValueError("Symbolic execution started with invalid parameters")
:param main_address:
:param creation_code:
:param contract_name:
"""
log.debug("Starting LASER execution") log.debug("Starting LASER execution")
for hook in self._start_sym_exec_hooks: for hook in self._start_sym_exec_hooks:
hook() hook()
@ -130,11 +133,12 @@ class LaserEVM:
time_handler.start_execution(self.execution_timeout) time_handler.start_execution(self.execution_timeout)
self.time = datetime.now() self.time = datetime.now()
if main_address: if pre_configuration_mode:
log.info("Starting message call transaction to {}".format(main_address)) self.open_states = [world_state]
self._execute_transactions(main_address) log.info("Starting message call transaction to {}".format(target_address))
self._execute_transactions(symbol_factory.BitVecVal(target_address, 256))
elif creation_code: elif scratch_mode:
log.info("Starting contract creation transaction") log.info("Starting contract creation transaction")
created_account = execute_contract_creation( created_account = execute_contract_creation(
self, creation_code, contract_name self, creation_code, contract_name
@ -355,7 +359,7 @@ class LaserEVM:
if not revert_changes: if not revert_changes:
return_global_state.world_state = copy(global_state.world_state) return_global_state.world_state = copy(global_state.world_state)
return_global_state.environment.active_account = global_state.accounts[ return_global_state.environment.active_account = global_state.accounts[
return_global_state.environment.active_account.address return_global_state.environment.active_account.address.value
] ]
# Execute the post instruction handler # Execute the post instruction handler
@ -389,19 +393,6 @@ class LaserEVM:
self._new_node_state( self._new_node_state(
state, JumpType.CONDITIONAL, state.mstate.constraints[-1] state, JumpType.CONDITIONAL, state.mstate.constraints[-1]
) )
elif opcode in ("CALL", "CALLCODE", "DELEGATECALL", "STATICCALL"):
assert len(new_states) <= 1
for state in new_states:
self._new_node_state(state, JumpType.CALL)
# Keep track of added contracts so the graph can be generated properly
if (
state.environment.active_account.contract_name
not in self.world_state.accounts.keys()
):
self.world_state.accounts[
state.environment.active_account.address
] = state.environment.active_account
elif opcode == "RETURN": elif opcode == "RETURN":
for state in new_states: for state in new_states:
self._new_node_state(state, JumpType.RETURN) self._new_node_state(state, JumpType.RETURN)

@ -2,25 +2,32 @@
symbolic values.""" symbolic values."""
import logging import logging
from mythril.laser.smt import symbol_factory
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from mythril.laser.ethereum.cfg import Node, Edge, JumpType from mythril.laser.ethereum.cfg import Node, Edge, JumpType
from mythril.laser.ethereum.state.calldata import BaseCalldata, SymbolicCalldata
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.calldata import SymbolicCalldata
from mythril.laser.ethereum.state.world_state import WorldState
from mythril.laser.ethereum.transaction.transaction_models import ( from mythril.laser.ethereum.transaction.transaction_models import (
MessageCallTransaction, MessageCallTransaction,
ContractCreationTransaction, ContractCreationTransaction,
get_next_transaction_id, get_next_transaction_id,
BaseTransaction,
) )
from mythril.laser.smt import symbol_factory, Or, BitVec
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
CREATOR_ADDRESS = 0xAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFE CREATOR_ADDRESS = 0xAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFE
ATTACKER_ADDRESS = 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF ATTACKER_ADDRESS = 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
ACTOR_ADDRESSES = [
symbol_factory.BitVecVal(0xAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFE, 256),
symbol_factory.BitVecVal(0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF, 256),
symbol_factory.BitVecVal(0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEE, 256),
]
def execute_message_call(laser_evm, callee_address: str) -> None: def execute_message_call(laser_evm, callee_address: BitVec) -> None:
"""Executes a message call transaction from all open states. """Executes a message call transaction from all open states.
:param laser_evm: :param laser_evm:
@ -46,7 +53,9 @@ def execute_message_call(laser_evm, callee_address: str) -> None:
origin=symbol_factory.BitVecSym( origin=symbol_factory.BitVecSym(
"origin{}".format(next_transaction_id), 256 "origin{}".format(next_transaction_id), 256
), ),
caller=symbol_factory.BitVecVal(ATTACKER_ADDRESS, 256), caller=symbol_factory.BitVecSym(
"sender_{}".format(next_transaction_id), 256
),
callee_account=open_world_state[callee_address], callee_account=open_world_state[callee_address],
call_data=SymbolicCalldata(next_transaction_id), call_data=SymbolicCalldata(next_transaction_id),
call_value=symbol_factory.BitVecSym( call_value=symbol_factory.BitVecSym(
@ -69,12 +78,14 @@ def execute_contract_creation(
:return: :return:
""" """
# TODO: Resolve circular import between .transaction and ..svm to import LaserEVM here # TODO: Resolve circular import between .transaction and ..svm to import LaserEVM here
open_states = laser_evm.open_states[:]
del laser_evm.open_states[:] del laser_evm.open_states[:]
new_account = laser_evm.world_state.create_account( world_state = WorldState()
open_states = [world_state]
new_account = world_state.create_account(
0, concrete_storage=True, dynamic_loader=None, creator=CREATOR_ADDRESS 0, concrete_storage=True, dynamic_loader=None, creator=CREATOR_ADDRESS
) )
if contract_name: if contract_name:
new_account.contract_name = contract_name new_account.contract_name = contract_name
@ -104,7 +115,7 @@ def execute_contract_creation(
return new_account return new_account
def _setup_global_state_for_execution(laser_evm, transaction) -> None: def _setup_global_state_for_execution(laser_evm, transaction: BaseTransaction) -> 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 laser_evm:
@ -114,6 +125,10 @@ def _setup_global_state_for_execution(laser_evm, transaction) -> None:
global_state = transaction.initial_global_state() global_state = transaction.initial_global_state()
global_state.transaction_stack.append((transaction, None)) global_state.transaction_stack.append((transaction, None))
global_state.mstate.constraints.append(
Or(*[transaction.caller == actor for actor in ACTOR_ADDRESSES])
)
new_node = Node( new_node = Node(
global_state.environment.active_account.contract_name, global_state.environment.active_account.contract_name,
function_name=global_state.environment.active_function_name, function_name=global_state.environment.active_function_name,

@ -111,8 +111,19 @@ class BaseTransaction:
# Initialize the execution environment # Initialize the execution environment
global_state = GlobalState(self.world_state, environment, None) global_state = GlobalState(self.world_state, environment, None)
global_state.environment.active_function_name = active_function global_state.environment.active_function_name = active_function
sender = environment.sender
receiver = environment.active_account.address
value = environment.callvalue
global_state.world_state.balances[sender] -= value
global_state.world_state.balances[receiver] += value
return global_state return global_state
def initial_global_state(self) -> GlobalState:
raise NotImplementedError
class MessageCallTransaction(BaseTransaction): class MessageCallTransaction(BaseTransaction):
"""Transaction object models an transaction.""" """Transaction object models an transaction."""
@ -143,6 +154,7 @@ class MessageCallTransaction(BaseTransaction):
:param revert: :param revert:
""" """
self.return_data = return_data self.return_data = return_data
raise TransactionEndSignal(global_state, revert) raise TransactionEndSignal(global_state, revert)
@ -190,7 +202,9 @@ class ContractCreationTransaction(BaseTransaction):
contract_code = bytes.hex(array.array("B", return_data).tostring()) contract_code = bytes.hex(array.array("B", return_data).tostring())
global_state.environment.active_account.code.assign_bytecode(contract_code) global_state.environment.active_account.code.assign_bytecode(contract_code)
self.return_data = global_state.environment.active_account.address self.return_data = str(
hex(global_state.environment.active_account.address.value)
)
assert global_state.environment.active_account.code.instruction_list != [] assert global_state.environment.active_account.code.instruction_list != []
raise TransactionEndSignal(global_state, revert=revert) raise TransactionEndSignal(global_state, revert=revert)

@ -90,15 +90,16 @@ def And(*args: Union[Bool, bool]) -> Bool:
return Bool(z3.And([a.raw for a in args_list]), union) return Bool(z3.And([a.raw for a in args_list]), union)
def Or(a: Bool, b: Bool) -> Bool: def Or(*args: Union[Bool, bool]) -> Bool:
"""Create an or expression. """Create an or expression.
:param a: :param a:
:param b: :param b:
:return: :return:
""" """
union = a.annotations + b.annotations args_list = [arg if isinstance(arg, Bool) else Bool(arg) for arg in args]
return Bool(z3.Or(a.raw, b.raw), annotations=union) union = [arg.annotations for arg in args_list]
return Bool(z3.Or([a.raw for a in args_list]), annotations=union)
def Not(a: Bool) -> Bool: def Not(a: Bool) -> Bool:

@ -22,16 +22,16 @@ class SourceMapping:
class SolidityFile: class SolidityFile:
"""Representation of a file containing Solidity code.""" """Representation of a file containing Solidity code."""
def __init__(self, filename: str, data: str, full_contract_source: Set[str]): def __init__(self, filename: str, data: str, full_contract_src_maps: Set[str]):
""" """
Metadata class containing data regarding a specific solidity file Metadata class containing data regarding a specific solidity file
:param filename: The filename of the solidity file :param filename: The filename of the solidity file
:param data: The code of the solidity file :param data: The code of the solidity file
:param full_contract_source: The set of contract source mappings of all the contracts in the file :param full_contract_src_maps: The set of contract source mappings of all the contracts in the file
""" """
self.filename = filename self.filename = filename
self.data = data self.data = data
self.full_contract_source = full_contract_source self.full_contract_src_maps = full_contract_src_maps
class SourceCodeInfo: class SourceCodeInfo:
@ -78,11 +78,11 @@ class SolidityContract(EVMContract):
for filename in data["sourceList"]: for filename in data["sourceList"]:
with open(filename, "r", encoding="utf-8") as file: with open(filename, "r", encoding="utf-8") as file:
code = file.read() code = file.read()
full_contract_sources = self.get_full_contract_sources( full_contract_src_maps = self.get_full_contract_src_maps(
data["sources"][filename]["AST"] data["sources"][filename]["AST"]
) )
self.solidity_files.append( self.solidity_files.append(
SolidityFile(filename, code, full_contract_sources) SolidityFile(filename, code, full_contract_src_maps)
) )
has_contract = False has_contract = False
@ -132,17 +132,17 @@ class SolidityContract(EVMContract):
super().__init__(code, creation_code, name=name) super().__init__(code, creation_code, name=name)
@staticmethod @staticmethod
def get_full_contract_sources(ast: Dict) -> Set[str]: def get_full_contract_src_maps(ast: Dict) -> Set[str]:
""" """
Takes a solc AST and gets the src mappings for all the contracts defined in the top level of the ast Takes a solc AST and gets the src mappings for all the contracts defined in the top level of the ast
:param ast: AST of the contract :param ast: AST of the contract
:return: The source map :return: The source maps
""" """
source_map = set() source_maps = set()
for child in ast["children"]: for child in ast["children"]:
if "contractKind" in child["attributes"]: if "contractKind" in child["attributes"]:
source_map.add(child["src"]) source_maps.add(child["src"])
return source_map return source_maps
def get_source_info(self, address, constructor=False): def get_source_info(self, address, constructor=False):
""" """
@ -181,7 +181,7 @@ class SolidityContract(EVMContract):
# Handle the common code src map for the entire code. # Handle the common code src map for the entire code.
if ( if (
"{}:{}:{}".format(offset, length, file_index) "{}:{}:{}".format(offset, length, file_index)
in self.solidity_files[file_index].full_contract_source in self.solidity_files[file_index].full_contract_src_maps
): ):
return True return True

@ -4,4 +4,4 @@ This file is suitable for sourcing inside POSIX shell, e.g. bash as well
as for importing into Python. as for importing into Python.
""" """
VERSION = "v0.20.4" # NOQA VERSION = "v0.20.6" # NOQA

@ -1,8 +1,9 @@
from mythril.laser.ethereum.svm import LaserEVM from mythril.laser.ethereum.svm import LaserEVM
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.world_state import WorldState
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from mythril.laser.ethereum.transaction.concolic import execute_message_call from mythril.laser.ethereum.transaction.concolic import execute_message_call
from mythril.laser.smt import Expression, BitVec from mythril.laser.smt import Expression, BitVec, symbol_factory
from mythril.analysis.solver import get_model from mythril.analysis.solver import get_model
from datetime import datetime from datetime import datetime
@ -82,25 +83,27 @@ def test_vmtest(
# Arrange # Arrange
if test_name == "gasprice": if test_name == "gasprice":
return return
accounts = {}
world_state = WorldState()
for address, details in pre_condition.items(): for address, details in pre_condition.items():
account = Account(address) account = Account(address)
account.code = Disassembly(details["code"][2:]) account.code = Disassembly(details["code"][2:])
account.balance = int(details["balance"], 16)
account.nonce = int(details["nonce"], 16) account.nonce = int(details["nonce"], 16)
world_state.put_account(account)
account.set_balance(int(details["balance"], 16))
accounts[address] = account laser_evm = LaserEVM()
laser_evm.open_states = [world_state]
laser_evm = LaserEVM(accounts)
# Act # Act
laser_evm.time = datetime.now() laser_evm.time = datetime.now()
final_states = execute_message_call( final_states = execute_message_call(
laser_evm, laser_evm,
callee_address=action["address"], callee_address=symbol_factory.BitVecVal(int(action["address"], 16), 256),
caller_address=action["caller"], caller_address=symbol_factory.BitVecVal(int(action["caller"], 16), 256),
origin_address=binascii.a2b_hex(action["origin"][2:]), origin_address=symbol_factory.BitVecVal(int(action["origin"], 16), 256),
code=action["code"][2:], code=action["code"][2:],
gas_limit=int(action["gas"], 16), gas_limit=int(action["gas"], 16),
data=binascii.a2b_hex(action["data"][2:]), data=binascii.a2b_hex(action["data"][2:]),
@ -132,7 +135,7 @@ def test_vmtest(
) )
for address, details in post_condition.items(): for address, details in post_condition.items():
account = world_state[address] account = world_state[symbol_factory.BitVecVal(int(address, 16), 256)]
assert account.nonce == int(details["nonce"], 16) assert account.nonce == int(details["nonce"], 16)
assert account.code.bytecode == details["code"][2:] assert account.code.bytecode == details["code"][2:]

@ -1,6 +1,8 @@
from mythril.disassembler.disassembly import Disassembly from mythril.disassembler.disassembly import Disassembly
from mythril.laser.ethereum import svm from mythril.laser.ethereum import svm
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.world_state import WorldState
import mythril.laser.ethereum.cfg as cfg import mythril.laser.ethereum.cfg as cfg
@ -18,15 +20,17 @@ def test_intercontract_call():
) )
callee_address = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" callee_address = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
world_state = WorldState()
caller_account = Account(caller_address, caller_code, contract_name="Caller") caller_account = Account(caller_address, caller_code, contract_name="Caller")
callee_account = Account(callee_address, callee_code, contract_name="Callee") callee_account = Account(callee_address, callee_code, contract_name="Callee")
world_state.put_account(callee_account)
world_state.put_account(caller_account)
accounts = {caller_address: caller_account, callee_address: callee_account} laser = svm.LaserEVM()
laser = svm.LaserEVM(accounts)
# Act # Act
laser.sym_exec(caller_address) laser.sym_exec(world_state=world_state, target_address=int(caller_address, 16))
# Assert # Assert
# Initial node starts in contract caller # Initial node starts in contract caller

@ -9,6 +9,8 @@ from mythril.laser.ethereum.transaction import (
from mythril.laser.ethereum.svm import LaserEVM from mythril.laser.ethereum.svm import LaserEVM
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.world_state import WorldState from mythril.laser.ethereum.state.world_state import WorldState
from mythril.laser.smt import symbol_factory
import unittest.mock as mock import unittest.mock as mock
from unittest.mock import MagicMock from unittest.mock import MagicMock
@ -29,7 +31,7 @@ def test_execute_message_call(mocked_setup: MagicMock):
laser_evm = LaserEVM({}) laser_evm = LaserEVM({})
world_state = WorldState() world_state = WorldState()
world_state.accounts["address"] = Account("address") world_state.put_account(Account("0x0"))
laser_evm.open_states = [world_state] laser_evm.open_states = [world_state]
laser_evm.exec = MagicMock() laser_evm.exec = MagicMock()
@ -37,7 +39,7 @@ def test_execute_message_call(mocked_setup: MagicMock):
mocked_setup.side_effect = _is_message_call mocked_setup.side_effect = _is_message_call
# Act # Act
execute_message_call(laser_evm, "address") execute_message_call(laser_evm, symbol_factory.BitVecVal(0, 256))
# Assert # Assert
# laser_evm.exec.assert_called_once() # laser_evm.exec.assert_called_once()

@ -3,6 +3,7 @@ from mythril.mythril import MythrilDisassembler
from mythril.laser.ethereum.state.account import Account from mythril.laser.ethereum.state.account import Account
from mythril.laser.ethereum.state.machine_state import MachineState from mythril.laser.ethereum.state.machine_state import MachineState
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum.state.world_state import WorldState
from mythril.laser.ethereum import svm from mythril.laser.ethereum import svm
from tests import BaseTestCase from tests import BaseTestCase
@ -29,13 +30,6 @@ IDENTITY_TEST[1] = (hex(476934798798347), False)
def _all_info(laser): def _all_info(laser):
accounts = {}
for address, _account in laser.world_state.accounts.items():
account = _account.as_dict
account["code"] = account["code"].instruction_list
account["balance"] = str(account["balance"])
accounts[address] = account
nodes = {} nodes = {}
for uid, node in laser.nodes.items(): for uid, node in laser.nodes.items():
states = [] states = []
@ -66,7 +60,6 @@ def _all_info(laser):
edges = [edge.as_dict for edge in laser.edges] edges = [edge.as_dict for edge in laser.edges]
return { return {
"accounts": accounts,
"nodes": nodes, "nodes": nodes,
"edges": edges, "edges": edges,
"total_states": laser.total_states, "total_states": laser.total_states,
@ -85,13 +78,13 @@ class NativeTests(BaseTestCase):
"""""" """"""
disassembly = SolidityContract( disassembly = SolidityContract(
"./tests/native_tests.sol", "./tests/native_tests.sol",
solc_binary=MythrilDisassembler._init_solc_binary("0.5.0"), solc_binary=MythrilDisassembler._init_solc_binary("0.5.3"),
).disassembly ).disassembly
account = Account("0x0000000000000000000000000000000000000000", disassembly) account = Account("0x0000000000000000000000000000000000000000", disassembly)
accounts = {account.address: account} world_state = WorldState()
world_state.put_account(account)
laser = svm.LaserEVM(accounts, max_depth=100, transaction_count=1) laser = svm.LaserEVM(max_depth=100, transaction_count=1)
laser.sym_exec(account.address) laser.sym_exec(world_state=world_state, target_address=account.address.value)
laser_info = str(_all_info(laser)) laser_info = str(_all_info(laser))

@ -32,7 +32,7 @@ def _generate_report(input_file):
contract = EVMContract(input_file.read_text(), enable_online_lookup=False) contract = EVMContract(input_file.read_text(), enable_online_lookup=False)
sym = SymExecWrapper( sym = SymExecWrapper(
contract, contract,
address=(util.get_indexed_address(0)), address=0xAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFEAFFE,
strategy="dfs", strategy="dfs",
execution_timeout=30, execution_timeout=30,
transaction_count=1, transaction_count=1,

@ -1,36 +0,0 @@
{
"error": null,
"issues": [
{
"address": 158,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The arithmetic operation can result in integer overflow.\n",
"function": "_function_0x83f12fec",
"swc-id": "101",
"title": "Integer Overflow",
"type": "Warning"
},
{
"address": 278,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The arithmetic operation can result in integer overflow.\n",
"function": "_function_0x83f12fec",
"swc-id": "101",
"title": "Integer Overflow",
"type": "Warning"
},
{
"address": 378,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The substraction can result in an integer underflow.\n",
"function": "_function_0x83f12fec",
"swc-id": "101",
"title": "Integer Underflow",
"type": "Warning"
}
],
"success": true
}

@ -1,34 +0,0 @@
# Analysis results for test-filename.sol
## Integer Overflow
- SWC ID: 101
- Type: Warning
- Contract: Unknown
- Function name: `_function_0x83f12fec`
- PC address: 158
### Description
The arithmetic operation can result in integer overflow.
## Integer Overflow
- SWC ID: 101
- Type: Warning
- Contract: Unknown
- Function name: `_function_0x83f12fec`
- PC address: 278
### Description
The arithmetic operation can result in integer overflow.
## Integer Underflow
- SWC ID: 101
- Type: Warning
- Contract: Unknown
- Function name: `_function_0x83f12fec`
- PC address: 378
### Description
The substraction can result in an integer underflow.

@ -1,30 +0,0 @@
==== Integer Overflow ====
SWC ID: 101
Type: Warning
Contract: Unknown
Function name: _function_0x83f12fec
PC address: 158
The arithmetic operation can result in integer overflow.
--------------------
==== Integer Overflow ====
SWC ID: 101
Type: Warning
Contract: Unknown
Function name: _function_0x83f12fec
PC address: 278
The arithmetic operation can result in integer overflow.
--------------------
==== Integer Underflow ====
SWC ID: 101
Type: Warning
Contract: Unknown
Function name: _function_0x83f12fec
PC address: 378
The substraction can result in an integer underflow.
--------------------

@ -1 +1,11 @@
[{"issues": [], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0x3746c7c2ae7b0d4c3f8b1905df9a7ea169b9f93bec68a10a00b4c9d27a18c6fb"], "sourceType": "raw-bytecode"}] [
{
"issues": [],
"meta": {},
"sourceFormat": "evm-byzantium-bytecode",
"sourceList": [
"0x3746c7c2ae7b0d4c3f8b1905df9a7ea169b9f93bec68a10a00b4c9d27a18c6fb"
],
"sourceType": "raw-bytecode"
}
]

@ -1 +1,11 @@
[{"issues": [], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0x0e6f727bb3301e02d3be831bf34357522fd2f1d40e90dff8e2214553b06b5f6c"], "sourceType": "raw-bytecode"}] [
{
"issues": [],
"meta": {},
"sourceFormat": "evm-byzantium-bytecode",
"sourceList": [
"0x0e6f727bb3301e02d3be831bf34357522fd2f1d40e90dff8e2214553b06b5f6c"
],
"sourceType": "raw-bytecode"
}
]

@ -1 +1,11 @@
[{"issues": [], "meta": {}, "sourceFormat": "evm-byzantium-bytecode", "sourceList": ["0x11a78eb09819f505ba4f10747e6d1f7a44480e602c67573b7abac2f733a85d93"], "sourceType": "raw-bytecode"}] [
{
"issues": [],
"meta": {},
"sourceFormat": "evm-byzantium-bytecode",
"sourceList": [
"0x11a78eb09819f505ba4f10747e6d1f7a44480e602c67573b7abac2f733a85d93"
],
"sourceType": "raw-bytecode"
}
]

@ -26,6 +26,19 @@
"sourceMap": null, "sourceMap": null,
"swc-id": "101", "swc-id": "101",
"title": "Integer Underflow" "title": "Integer Underflow"
},
{
"address": 725,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The binary addition can overflow.\nThe operands of the addition operation are not sufficiently constrained. The addition could therefore result in an integer overflow. Prevent the overflow by checking inputs or ensure sure that the overflow is caught by an assertion.",
"function": "sendeth(address,uint256)",
"max_gas_used": 78155,
"min_gas_used": 17019,
"severity": "High",
"sourceMap": null,
"swc-id": "101",
"title": "Integer Overflow"
} }
], ],
"success": true "success": true

@ -34,6 +34,23 @@
"severity": "High", "severity": "High",
"swcID": "SWC-101", "swcID": "SWC-101",
"swcTitle": "Integer Overflow and Underflow" "swcTitle": "Integer Overflow and Underflow"
},
{
"description": {
"head": "The binary addition can overflow.",
"tail": "The operands of the addition operation are not sufficiently constrained. The addition could therefore result in an integer overflow. Prevent the overflow by checking inputs or ensure sure that the overflow is caught by an assertion."
},
"extra": {
"discoveryTime": "<DISCOVERY-TIME-DATA>"
},
"locations": [
{
"sourceMap": "725:1:0"
}
],
"severity": "High",
"swcID": "SWC-101",
"swcTitle": "Integer Overflow and Underflow"
} }
], ],
"meta": {}, "meta": {},

@ -25,3 +25,16 @@ The operands of the subtraction operation are not sufficiently constrained. The
The binary subtraction can underflow. The binary subtraction can underflow.
The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion. The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion.
## Integer Overflow
- SWC ID: 101
- Severity: High
- Contract: Unknown
- Function name: `sendeth(address,uint256)`
- PC address: 725
- Estimated Gas Usage: 17019 - 78155
### Description
The binary addition can overflow.
The operands of the addition operation are not sufficiently constrained. The addition could therefore result in an integer overflow. Prevent the overflow by checking inputs or ensure sure that the overflow is caught by an assertion.

@ -20,3 +20,14 @@ The binary subtraction can underflow.
The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion. The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion.
-------------------- --------------------
==== Integer Overflow ====
SWC ID: 101
Severity: High
Contract: Unknown
Function name: sendeth(address,uint256)
PC address: 725
Estimated Gas Usage: 17019 - 78155
The binary addition can overflow.
The operands of the addition operation are not sufficiently constrained. The addition could therefore result in an integer overflow. Prevent the overflow by checking inputs or ensure sure that the overflow is caught by an assertion.
--------------------

@ -1,166 +0,0 @@
{
"success": true,
"error": null,
"issues": [
{
"title": "Ether send",
"description": "In the function `_function_0x4229616d` a non-zero amount of Ether is sent to an address taken from storage slot 5.\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\n\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.",
"function": "_function_0x4229616d",
"type": "Warning",
"address": 1599,
"debug": "<DEBUG-DATA>"
},
{
"title": "Ether send",
"description": "In the function `_function_0xb4022950` a non-zero amount of Ether is sent to an address taken from storage slot 5.\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\n\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.",
"function": "_function_0xb4022950",
"type": "Warning",
"address": 1940,
"debug": "<DEBUG-DATA>"
},
{
"title": "Ether send",
"description": "In the function `_function_0xb4022950` a non-zero amount of Ether is sent to an address taken from storage slot 5.\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\n\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.",
"function": "_function_0xb4022950",
"type": "Warning",
"address": 2582,
"debug": "<DEBUG-DATA>"
},
{
"title": "Exception state",
"description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ",
"function": "_function_0x57d4021b",
"type": "Informational",
"address": 1653,
"debug": "<DEBUG-DATA>"
},
{
"title": "Exception state",
"description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ",
"function": "_function_0x9dbc4f9b",
"type": "Informational",
"address": 2085,
"debug": "<DEBUG-DATA>"
},
{
"title": "Invariant branch condition",
"description": "Found a conditional jump which always follows the same branch",
"function": "fallback",
"type": "Informational",
"address": 3111,
"debug": "<DEBUG-DATA>"
},
{
"title": "Invariant branch condition",
"description": "Found a conditional jump which always follows the same branch",
"function": "fallback",
"type": "Informational",
"address": 3140,
"debug": "<DEBUG-DATA>"
},
{
"title": "Invariant branch condition",
"description": "Found a conditional jump which always follows the same branch",
"function": "fallback",
"type": "Informational",
"address": 2950,
"debug": "<DEBUG-DATA>"
},
{
"title": "Invariant branch condition",
"description": "Found a conditional jump which always follows the same branch",
"function": "fallback",
"type": "Informational",
"address": 1268,
"debug": "<DEBUG-DATA>"
},
{
"title": "Invariant branch condition",
"description": "Found a conditional jump which always follows the same branch",
"function": "_function_0x09dfdc71",
"type": "Informational",
"address": 310,
"debug": "<DEBUG-DATA>"
},
{
"title": "Invariant branch condition",
"description": "Found a conditional jump which always follows the same branch",
"function": "_function_0x09dfdc71",
"type": "Informational",
"address": 1316,
"debug": "<DEBUG-DATA>"
},
{
"title": "Invariant branch condition",
"description": "Found a conditional jump which always follows the same branch",
"function": "_function_0x253459e3",
"type": "Informational",
"address": 1375,
"debug": "<DEBUG-DATA>"
},
{
"title": "Invariant branch condition",
"description": "Found a conditional jump which always follows the same branch",
"function": "_function_0x4229616d",
"type": "Informational",
"address": 1511,
"debug": "<DEBUG-DATA>"
},
{
"title": "Invariant branch condition",
"description": "Found a conditional jump which always follows the same branch",
"function": "_function_0x57d4021b",
"type": "Informational",
"address": 1679,
"debug": "<DEBUG-DATA>"
},
{
"title": "Invariant branch condition",
"description": "Found a conditional jump which always follows the same branch",
"function": "_function_0x6fbaaa1e",
"type": "Informational",
"address": 618,
"debug": "<DEBUG-DATA>"
},
{
"title": "Invariant branch condition",
"description": "Found a conditional jump which always follows the same branch",
"function": "_function_0x8a5fb3ca",
"type": "Informational",
"address": 805,
"debug": "<DEBUG-DATA>"
},
{
"title": "Invariant branch condition",
"description": "Found a conditional jump which always follows the same branch",
"function": "_function_0x9dbc4f9b",
"type": "Informational",
"address": 2187,
"debug": "<DEBUG-DATA>"
},
{
"title": "Unchecked CALL return value",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "_function_0x4229616d",
"type": "Informational",
"address": 1599,
"debug": "<DEBUG-DATA>"
},
{
"title": "Unchecked CALL return value",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "_function_0xb4022950",
"type": "Informational",
"address": 1940,
"debug": "<DEBUG-DATA>"
},
{
"title": "Unchecked CALL return value",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "_function_0xb4022950",
"type": "Informational",
"address": 2582,
"debug": "<DEBUG-DATA>"
}
]
}

@ -1,238 +0,0 @@
# Analysis results for test-filename.sol
## Ether send
- Type: Warning
- Contract: Unknown
- Function name: `_function_0x4229616d`
- PC address: 1599
### Description
In the function `_function_0x4229616d` a non-zero amount of Ether is sent to an address taken from storage slot 5.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
## Ether send
- Type: Warning
- Contract: Unknown
- Function name: `_function_0xb4022950`
- PC address: 1940
### Description
In the function `_function_0xb4022950` a non-zero amount of Ether is sent to an address taken from storage slot 5.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
## Ether send
- Type: Warning
- Contract: Unknown
- Function name: `_function_0xb4022950`
- PC address: 2582
### Description
In the function `_function_0xb4022950` a non-zero amount of Ether is sent to an address taken from storage slot 5.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
## Exception state
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x57d4021b`
- PC address: 1653
### Description
A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
## Exception state
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x9dbc4f9b`
- PC address: 2085
### Description
A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
## Tautology
- Type: Informational
- Contract: Unknown
- Function name: `fallback`
- PC address: 3111
### Description
Found a conditional jump which always follows the same branch, value: True
## Tautology
- Type: Informational
- Contract: Unknown
- Function name: `fallback`
- PC address: 3140
### Description
Found a conditional jump which always follows the same branch, value: True
## Tautology
- Type: Informational
- Contract: Unknown
- Function name: `fallback`
- PC address: 2950
### Description
Found a conditional jump which always follows the same branch, value: True
## Tautology
- Type: Informational
- Contract: Unknown
- Function name: `fallback`
- PC address: 1268
### Description
Found a conditional jump which always follows the same branch, value: True
## Tautology
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x09dfdc71`
- PC address: 310
### Description
Found a conditional jump which always follows the same branch, value: False
## Tautology
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x09dfdc71`
- PC address: 1316
### Description
Found a conditional jump which always follows the same branch, value: True
## Tautology
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x253459e3`
- PC address: 1375
### Description
Found a conditional jump which always follows the same branch, value: True
## Tautology
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x4229616d`
- PC address: 1511
### Description
Found a conditional jump which always follows the same branch, value: True
## Tautology
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x57d4021b`
- PC address: 1679
### Description
Found a conditional jump which always follows the same branch, value: True
## Tautology
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x6fbaaa1e`
- PC address: 618
### Description
Found a conditional jump which always follows the same branch, value: False
## Tautology
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x8a5fb3ca`
- PC address: 805
### Description
Found a conditional jump which always follows the same branch, value: False
## Tautology
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x9dbc4f9b`
- PC address: 2187
### Description
Found a conditional jump which always follows the same branch, value: True
## Unchecked CALL return value
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x4229616d`
- PC address: 1599
### Description
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
## Unchecked CALL return value
- Type: Informational
- Contract: Unknown
- Function name: `_function_0xb4022950`
- PC address: 1940
### Description
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
## Unchecked CALL return value
- Type: Informational
- Contract: Unknown
- Function name: `_function_0xb4022950`
- PC address: 2582
### Description
The return value of an external call is not checked. Note that execution continue even if the called contract throws.

@ -1,177 +0,0 @@
==== Ether send ====
Type: Warning
Contract: Unknown
Function name: _function_0x4229616d
PC address: 1599
In the function `_function_0x4229616d` a non-zero amount of Ether is sent to an address taken from storage slot 5.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
--------------------
==== Ether send ====
Type: Warning
Contract: Unknown
Function name: _function_0xb4022950
PC address: 1940
In the function `_function_0xb4022950` a non-zero amount of Ether is sent to an address taken from storage slot 5.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
--------------------
==== Ether send ====
Type: Warning
Contract: Unknown
Function name: _function_0xb4022950
PC address: 2582
In the function `_function_0xb4022950` a non-zero amount of Ether is sent to an address taken from storage slot 5.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
--------------------
==== Exception state ====
Type: Informational
Contract: Unknown
Function name: _function_0x57d4021b
PC address: 1653
A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
--------------------
==== Exception state ====
Type: Informational
Contract: Unknown
Function name: _function_0x9dbc4f9b
PC address: 2085
A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
--------------------
==== Tautology ====
Type: Informational
Contract: Unknown
Function name: fallback
PC address: 3111
Found a conditional jump which always follows the same branch, value: True
--------------------
==== Tautology ====
Type: Informational
Contract: Unknown
Function name: fallback
PC address: 3140
Found a conditional jump which always follows the same branch, value: True
--------------------
==== Tautology ====
Type: Informational
Contract: Unknown
Function name: fallback
PC address: 2950
Found a conditional jump which always follows the same branch, value: True
--------------------
==== Tautology ====
Type: Informational
Contract: Unknown
Function name: fallback
PC address: 1268
Found a conditional jump which always follows the same branch, value: True
--------------------
==== Tautology ====
Type: Informational
Contract: Unknown
Function name: _function_0x09dfdc71
PC address: 310
Found a conditional jump which always follows the same branch, value: False
--------------------
==== Tautology ====
Type: Informational
Contract: Unknown
Function name: _function_0x09dfdc71
PC address: 1316
Found a conditional jump which always follows the same branch, value: True
--------------------
==== Tautology ====
Type: Informational
Contract: Unknown
Function name: _function_0x253459e3
PC address: 1375
Found a conditional jump which always follows the same branch, value: True
--------------------
==== Tautology ====
Type: Informational
Contract: Unknown
Function name: _function_0x4229616d
PC address: 1511
Found a conditional jump which always follows the same branch, value: True
--------------------
==== Tautology ====
Type: Informational
Contract: Unknown
Function name: _function_0x57d4021b
PC address: 1679
Found a conditional jump which always follows the same branch, value: True
--------------------
==== Tautology ====
Type: Informational
Contract: Unknown
Function name: _function_0x6fbaaa1e
PC address: 618
Found a conditional jump which always follows the same branch, value: False
--------------------
==== Tautology ====
Type: Informational
Contract: Unknown
Function name: _function_0x8a5fb3ca
PC address: 805
Found a conditional jump which always follows the same branch, value: False
--------------------
==== Tautology ====
Type: Informational
Contract: Unknown
Function name: _function_0x9dbc4f9b
PC address: 2187
Found a conditional jump which always follows the same branch, value: True
--------------------
==== Unchecked CALL return value ====
Type: Informational
Contract: Unknown
Function name: _function_0x4229616d
PC address: 1599
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------
==== Unchecked CALL return value ====
Type: Informational
Contract: Unknown
Function name: _function_0xb4022950
PC address: 1940
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------
==== Unchecked CALL return value ====
Type: Informational
Contract: Unknown
Function name: _function_0xb4022950
PC address: 2582
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------

@ -26,6 +26,19 @@
"sourceMap": null, "sourceMap": null,
"swc-id": "101", "swc-id": "101",
"title": "Integer Underflow" "title": "Integer Underflow"
},
{
"address": 725,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The binary addition can overflow.\nThe operands of the addition operation are not sufficiently constrained. The addition could therefore result in an integer overflow. Prevent the overflow by checking inputs or ensure sure that the overflow is caught by an assertion.",
"function": "sendeth(address,uint256)",
"max_gas_used": 52861,
"min_gas_used": 11915,
"severity": "High",
"sourceMap": null,
"swc-id": "101",
"title": "Integer Overflow"
} }
], ],
"success": true "success": true

@ -34,6 +34,23 @@
"severity": "High", "severity": "High",
"swcID": "SWC-101", "swcID": "SWC-101",
"swcTitle": "Integer Overflow and Underflow" "swcTitle": "Integer Overflow and Underflow"
},
{
"description": {
"head": "The binary addition can overflow.",
"tail": "The operands of the addition operation are not sufficiently constrained. The addition could therefore result in an integer overflow. Prevent the overflow by checking inputs or ensure sure that the overflow is caught by an assertion."
},
"extra": {
"discoveryTime": "<DISCOVERY-TIME-DATA>"
},
"locations": [
{
"sourceMap": "725:1:0"
}
],
"severity": "High",
"swcID": "SWC-101",
"swcTitle": "Integer Overflow and Underflow"
} }
], ],
"meta": {}, "meta": {},

@ -25,3 +25,16 @@ The operands of the subtraction operation are not sufficiently constrained. The
The binary subtraction can underflow. The binary subtraction can underflow.
The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion. The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion.
## Integer Overflow
- SWC ID: 101
- Severity: High
- Contract: Unknown
- Function name: `sendeth(address,uint256)`
- PC address: 725
- Estimated Gas Usage: 11915 - 52861
### Description
The binary addition can overflow.
The operands of the addition operation are not sufficiently constrained. The addition could therefore result in an integer overflow. Prevent the overflow by checking inputs or ensure sure that the overflow is caught by an assertion.

@ -20,3 +20,14 @@ The binary subtraction can underflow.
The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion. The operands of the subtraction operation are not sufficiently constrained. The subtraction could therefore result in an integer underflow. Prevent the underflow by checking inputs or ensure sure that the underflow is caught by an assertion.
-------------------- --------------------
==== Integer Overflow ====
SWC ID: 101
Severity: High
Contract: Unknown
Function name: sendeth(address,uint256)
PC address: 725
Estimated Gas Usage: 11915 - 52861
The binary addition can overflow.
The operands of the addition operation are not sufficiently constrained. The addition could therefore result in an integer overflow. Prevent the overflow by checking inputs or ensure sure that the overflow is caught by an assertion.
--------------------

@ -1,46 +0,0 @@
{
"success": true,
"error": null,
"issues": [
{
"title": "Dependence on predictable environment variable",
"description": "In the function `_function_0xe9874106` the following predictable state variables are used to determine Ether recipient:\n- block.coinbase\n",
"function": "_function_0xe9874106",
"type": "Warning",
"address": 1285,
"debug": "<DEBUG-DATA>"
},
{
"title": "Ether send",
"description": "In the function `_function_0xe9874106` a non-zero amount of Ether is sent to an address taken from storage slot 0.\nThere is a check on storage index 0. This storage slot can be written to by calling the function `fallback`.\n\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.",
"function": "_function_0xe9874106",
"type": "Warning",
"address": 1285,
"debug": "<DEBUG-DATA>"
},
{
"title": "Exception state",
"description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ",
"function": "fallback",
"type": "Informational",
"address": 356,
"debug": "<DEBUG-DATA>"
},
{
"title": "Exception state",
"description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ",
"function": "_function_0xe9874106",
"type": "Informational",
"address": 146,
"debug": "<DEBUG-DATA>"
},
{
"title": "Transaction order dependence",
"description": "A possible transaction order independence vulnerability exists in function _function_0xe9874106. The value or direction of the call statement is determined from a tainted storage location",
"function": "_function_0xe9874106",
"type": "Warning",
"address": 1285,
"debug": "<DEBUG-DATA>"
}
]
}

@ -1,62 +0,0 @@
# Analysis results for test-filename.sol
## Dependence on predictable environment variable
- Type: Warning
- Contract: Unknown
- Function name: `_function_0xe9874106`
- PC address: 1285
### Description
In the function `_function_0xe9874106` the following predictable state variables are used to determine Ether recipient:
- block.coinbase
## Ether send
- Type: Warning
- Contract: Unknown
- Function name: `_function_0xe9874106`
- PC address: 1285
### Description
In the function `_function_0xe9874106` a non-zero amount of Ether is sent to an address taken from storage slot 0.
There is a check on storage index 0. This storage slot can be written to by calling the function `fallback`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
## Exception state
- Type: Informational
- Contract: Unknown
- Function name: `fallback`
- PC address: 356
### Description
A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
## Exception state
- Type: Informational
- Contract: Unknown
- Function name: `_function_0xe9874106`
- PC address: 146
### Description
A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
## Transaction order dependence
- Type: Warning
- Contract: Unknown
- Function name: `_function_0xe9874106`
- PC address: 1285
### Description
A possible transaction order independence vulnerability exists in function _function_0xe9874106. The value or direction of the call statement is determined from a tainted storage location

@ -1,46 +0,0 @@
==== Dependence on predictable environment variable ====
Type: Warning
Contract: Unknown
Function name: _function_0xe9874106
PC address: 1285
In the function `_function_0xe9874106` the following predictable state variables are used to determine Ether recipient:
- block.coinbase
--------------------
==== Ether send ====
Type: Warning
Contract: Unknown
Function name: _function_0xe9874106
PC address: 1285
In the function `_function_0xe9874106` a non-zero amount of Ether is sent to an address taken from storage slot 0.
There is a check on storage index 0. This storage slot can be written to by calling the function `fallback`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
--------------------
==== Exception state ====
Type: Informational
Contract: Unknown
Function name: fallback
PC address: 356
A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
--------------------
==== Exception state ====
Type: Informational
Contract: Unknown
Function name: _function_0xe9874106
PC address: 146
A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
--------------------
==== Transaction order dependence ====
Type: Warning
Contract: Unknown
Function name: _function_0xe9874106
PC address: 1285
A possible transaction order independence vulnerability exists in function _function_0xe9874106. The value or direction of the call statement is determined from a tainted storage location
--------------------
Loading…
Cancel
Save