Merge branch 'develop' into feature/docs

pull/845/head
Dominik Muhs 6 years ago
parent 0bdc7ed48e
commit d7f80023d7
  1. 2
      README.md
  2. 16
      mythril/analysis/modules/base.py
  3. 4
      mythril/analysis/modules/delegatecall.py
  4. 2
      mythril/analysis/modules/dependence_on_predictable_vars.py
  5. 4
      mythril/analysis/modules/deprecated_ops.py
  6. 2
      mythril/analysis/modules/ether_thief.py
  7. 2
      mythril/analysis/modules/exceptions.py
  8. 9
      mythril/analysis/modules/external_calls.py
  9. 412
      mythril/analysis/modules/integer.py
  10. 143
      mythril/analysis/modules/multiple_sends.py
  11. 7
      mythril/analysis/modules/suicide.py
  12. 1
      mythril/analysis/modules/transaction_order_dependence.py
  13. 130
      mythril/analysis/modules/unchecked_retval.py
  14. 22
      mythril/analysis/security.py
  15. 4
      mythril/analysis/solver.py
  16. 7
      mythril/analysis/symbolic.py
  17. 55
      mythril/laser/ethereum/call.py
  18. 123
      mythril/laser/ethereum/instructions.py
  19. 5
      mythril/laser/ethereum/state/account.py
  20. 4
      mythril/laser/ethereum/state/machine_state.py
  21. 26
      mythril/laser/smt/__init__.py
  22. 1
      tests/graph_test.py
  23. 6
      tests/native_test.py
  24. 103
      tests/testdata/outputs_expected/calls.sol.o.json
  25. 16
      tests/testdata/outputs_expected/calls.sol.o.markdown
  26. 16
      tests/testdata/outputs_expected/calls.sol.o.text
  27. 36
      tests/testdata/outputs_expected/kinds_of_calls.sol.o.json
  28. 30
      tests/testdata/outputs_expected/kinds_of_calls.sol.o.markdown
  29. 28
      tests/testdata/outputs_expected/kinds_of_calls.sol.o.text
  30. 58
      tests/testdata/outputs_expected/overflow.sol.o.json
  31. 20
      tests/testdata/outputs_expected/overflow.sol.o.markdown
  32. 19
      tests/testdata/outputs_expected/overflow.sol.o.text
  33. 43
      tests/testdata/outputs_expected/returnvalue.sol.o.json
  34. 4
      tests/testdata/outputs_expected/returnvalue.sol.o.markdown
  35. 4
      tests/testdata/outputs_expected/returnvalue.sol.o.text
  36. 58
      tests/testdata/outputs_expected/underflow.sol.o.json
  37. 20
      tests/testdata/outputs_expected/underflow.sol.o.markdown
  38. 19
      tests/testdata/outputs_expected/underflow.sol.o.text

@ -15,7 +15,7 @@ Mythril Classic is an open-source security analysis tool for Ethereum smart cont
Whether you want to contribute, need support, or want to learn what we have cooking for the future, our [Discord server](https://discord.gg/E3YrVtG) will serve your needs. Whether you want to contribute, need support, or want to learn what we have cooking for the future, our [Discord server](https://discord.gg/E3YrVtG) will serve your needs.
Oh and by the way, we're also building an easy-to-use security analysis platform (a.k.a. "the INFURA for smart contract security") that anybody can use to create purpose-built security tools. It's called [Mythril Platform](https://mythril.ai) and you should definitely [check it out](https://media.consensys.net/mythril-platform-api-is-upping-the-smart-contract-security-game-eee1d2642488). Oh and by the way, we're also building an easy-to-use security analysis platform (a.k.a. "the INFURA for smart contract security") that anybody can use to create purpose-built security tools. It's called [MythX](https://mythril.ai) and you should definitely [check it out](https://media.consensys.net/mythril-platform-api-is-upping-the-smart-contract-security-game-eee1d2642488).
## Installation and setup ## Installation and setup

@ -17,21 +17,15 @@ class DetectionModule:
self, self,
name: str, name: str,
swc_id: str, swc_id: str,
hooks: List[str],
description: str, description: str,
entrypoint: str = "post", entrypoint: str = "post",
) -> None: pre_hooks: List[str] = None,
"""Initialize a new detection module. post_hooks: List[str] = None,
):
:param name:
:param swc_id:
:param hooks:
:param description:
:param entrypoint:
"""
self.name = name self.name = name
self.swc_id = swc_id self.swc_id = swc_id
self.hooks = hooks self.pre_hooks = pre_hooks if pre_hooks else []
self.post_hooks = post_hooks if post_hooks else []
self.description = description self.description = description
if entrypoint not in ("post", "callback"): if entrypoint not in ("post", "callback"):
log.error( log.error(

@ -22,9 +22,9 @@ class DelegateCallModule(DetectionModule):
super().__init__( super().__init__(
name="DELEGATECALL Usage in Fallback Function", name="DELEGATECALL Usage in Fallback Function",
swc_id=DELEGATECALL_TO_UNTRUSTED_CONTRACT, swc_id=DELEGATECALL_TO_UNTRUSTED_CONTRACT,
hooks=["DELEGATECALL"],
description="Check for invocations of delegatecall(msg.data) in the fallback function.", description="Check for invocations of delegatecall(msg.data) in the fallback function.",
entrypoint="callback", entrypoint="callback",
pre_hooks=["DELEGATECALL"],
) )
self._issues = [] self._issues = []
@ -53,6 +53,8 @@ def _analyze_states(state: GlobalState) -> List[Issue]:
:return: returns the issues for that corresponding state :return: returns the issues for that corresponding state
""" """
call = get_call_from_state(state) call = get_call_from_state(state)
if call is None:
return []
issues = [] issues = []
if call.type is not "DELEGATECALL": if call.type is not "DELEGATECALL":

@ -24,13 +24,13 @@ class PredictableDependenceModule(DetectionModule):
super().__init__( super().__init__(
name="Dependence of Predictable Variables", name="Dependence of Predictable Variables",
swc_id="{} {}".format(TIMESTAMP_DEPENDENCE, PREDICTABLE_VARS_DEPENDENCE), swc_id="{} {}".format(TIMESTAMP_DEPENDENCE, PREDICTABLE_VARS_DEPENDENCE),
hooks=["CALL", "CALLCODE", "DELEGATECALL", "STATICCALL"],
description=( description=(
"Check for CALLs that send >0 Ether as a result of computation " "Check for CALLs that send >0 Ether as a result of computation "
"based on predictable variables such as block.coinbase, " "based on predictable variables such as block.coinbase, "
"block.gaslimit, block.timestamp, block.number" "block.gaslimit, block.timestamp, block.number"
), ),
entrypoint="callback", entrypoint="callback",
pre_hooks=["CALL", "CALLCODE", "DELEGATECALL", "STATICCALL"],
) )
self._issues = [] self._issues = []

@ -4,7 +4,9 @@ import logging
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.analysis.swc_data import DEPRICATED_FUNCTIONS_USAGE from mythril.analysis.swc_data import DEPRICATED_FUNCTIONS_USAGE
from mythril.analysis.modules.base import DetectionModule
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -65,9 +67,9 @@ class DeprecatedOperationsModule(DetectionModule):
super().__init__( super().__init__(
name="Deprecated Operations", name="Deprecated Operations",
swc_id=DEPRICATED_FUNCTIONS_USAGE, swc_id=DEPRICATED_FUNCTIONS_USAGE,
hooks=["ORIGIN", "CALLCODE"],
description=DESCRIPTION, description=DESCRIPTION,
entrypoint="callback", entrypoint="callback",
pre_hooks=["ORIGIN", "CALLCODE"],
) )
self._issues = [] self._issues = []

@ -92,9 +92,9 @@ class EtherThief(DetectionModule):
super().__init__( super().__init__(
name="Ether Thief", name="Ether Thief",
swc_id=UNPROTECTED_ETHER_WITHDRAWAL, swc_id=UNPROTECTED_ETHER_WITHDRAWAL,
hooks=["CALL"],
description=DESCRIPTION, description=DESCRIPTION,
entrypoint="callback", entrypoint="callback",
pre_hooks=["CALL"],
) )
self._issues = [] self._issues = []

@ -63,9 +63,9 @@ class ReachableExceptionsModule(DetectionModule):
super().__init__( super().__init__(
name="Reachable Exceptions", name="Reachable Exceptions",
swc_id=ASSERT_VIOLATION, swc_id=ASSERT_VIOLATION,
hooks=["ASSERT_FAIL"],
description="Checks whether any exception states are reachable.", description="Checks whether any exception states are reachable.",
entrypoint="callback", entrypoint="callback",
pre_hooks=["ASSERT_FAIL"],
) )
self._issues = [] self._issues = []

@ -3,12 +3,13 @@ calls."""
import logging import logging
from mythril.analysis import solver from mythril.analysis import solver
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.analysis.swc_data import REENTRANCY
from mythril.exceptions import UnsatError
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.smt import UGT, symbol_factory from mythril.laser.smt import UGT, symbol_factory
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.exceptions import UnsatError
import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -106,9 +107,9 @@ class ExternalCalls(DetectionModule):
super().__init__( super().__init__(
name="External calls", name="External calls",
swc_id=REENTRANCY, swc_id=REENTRANCY,
hooks=["CALL"],
description=DESCRIPTION, description=DESCRIPTION,
entrypoint="callback", entrypoint="callback",
pre_hooks=["CALL"],
) )
self._issues = [] self._issues = []

@ -1,26 +1,36 @@
"""This module contains the detection code for integer overflows and """This module contains the detection code for integer overflows and
underflows.""" underflows."""
import copy
import logging
from mythril.analysis import solver from mythril.analysis import solver
from mythril.analysis.modules.base import DetectionModule
from mythril.analysis.report import Issue from mythril.analysis.report import Issue
from mythril.analysis.swc_data import INTEGER_OVERFLOW_AND_UNDERFLOW from mythril.analysis.swc_data import INTEGER_OVERFLOW_AND_UNDERFLOW
from mythril.exceptions import UnsatError from mythril.exceptions import UnsatError
from mythril.laser.ethereum.taint_analysis import TaintRunner from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.analysis.modules.base import DetectionModule
from mythril.laser.smt import ( from mythril.laser.smt import (
BitVec,
BVAddNoOverflow, BVAddNoOverflow,
BVMulNoOverflow,
BVSubNoUnderflow, BVSubNoUnderflow,
Not, BVMulNoOverflow,
BitVec,
symbol_factory, symbol_factory,
Not,
Expression,
) )
import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class OverUnderflowAnnotation:
def __init__(self, overflowing_state: GlobalState, operator: str, constraint):
self.overflowing_state = overflowing_state
self.operator = operator
self.constraint = constraint
class IntegerOverflowUnderflowModule(DetectionModule): class IntegerOverflowUnderflowModule(DetectionModule):
"""This module searches for integer over- and underflows.""" """This module searches for integer over- and underflows."""
@ -29,331 +39,179 @@ class IntegerOverflowUnderflowModule(DetectionModule):
super().__init__( super().__init__(
name="Integer Overflow and Underflow", name="Integer Overflow and Underflow",
swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW, swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW,
hooks=["ADD", "MUL"],
description=( description=(
"For every SUB instruction, check if there's a possible state " "For every SUB instruction, check if there's a possible state "
"where op1 > op0. For every ADD, MUL instruction, check if " "where op1 > op0. For every ADD, MUL instruction, check if "
"there's a possible state where op1 + op0 > 2^32 - 1" "there's a possible state where op1 + op0 > 2^32 - 1"
), ),
entrypoint="callback",
pre_hooks=["ADD", "MUL", "SUB", "SSTORE", "JUMPI"],
) )
self._issues = []
@property
def issues(self):
return self._issues
def execute(self, statespace): def execute(self, state: GlobalState):
"""Executes analysis module for integer underflow and integer overflow. """Executes analysis module for integer underflow and integer overflow.
:param statespace: Statespace to analyse :param state: Statespace to analyse
:return: Found issues :return: Found issues
""" """
log.debug("Executing module: INTEGER") if state.get_current_instruction()["opcode"] == "ADD":
self._handle_add(state)
issues = [] elif state.get_current_instruction()["opcode"] == "MUL":
self._handle_mul(state)
elif state.get_current_instruction()["opcode"] == "SUB":
self._handle_sub(state)
elif state.get_current_instruction()["opcode"] == "SSTORE":
self._handle_sstore(state)
elif state.get_current_instruction()["opcode"] == "JUMPI":
self._handle_jumpi(state)
def _handle_add(self, state):
stack = state.mstate.stack
op0, op1 = (
self._make_bitvec_if_not(stack, -1),
self._make_bitvec_if_not(stack, -2),
)
c = Not(BVAddNoOverflow(op0, op1, False))
for k in statespace.nodes: # Check satisfiable
node = statespace.nodes[k] model = self._try_constraints(state.node.constraints, [c])
if model is None:
return
for state in node.states: annotation = OverUnderflowAnnotation(state, "add", c)
issues += self._check_integer_underflow(statespace, state, node) op0.annotate(annotation)
issues += self._check_integer_overflow(statespace, state, node)
return issues def _handle_mul(self, state):
stack = state.mstate.stack
op0, op1 = (
self._make_bitvec_if_not(stack, -1),
self._make_bitvec_if_not(stack, -2),
)
def _check_integer_overflow(self, statespace, state, node): c = Not(BVMulNoOverflow(op0, op1, False))
"""Checks for integer overflow.
:param statespace: statespace that is being examined # Check satisfiable
:param state: state from node to examine model = self._try_constraints(state.node.constraints, [c])
:param node: node to examine if model is None:
:return: found issue return
"""
issues = []
# Check the instruction annotation = OverUnderflowAnnotation(state, "multiply", c)
instruction = state.get_current_instruction() op0.annotate(annotation)
if instruction["opcode"] not in ("ADD", "MUL"):
return issues
# Formulate overflow constraints def _handle_sub(self, state):
stack = state.mstate.stack stack = state.mstate.stack
op0, op1 = stack[-1], stack[-2] op0, op1 = (
self._make_bitvec_if_not(stack, -1),
# An integer overflow is possible if op0 + op1 or op0 * op1 > MAX_UINT self._make_bitvec_if_not(stack, -2),
# Do a type check )
allowed_types = [int, BitVec] c = Not(BVSubNoUnderflow(op0, op1, False))
if not (type(op0) in allowed_types and type(op1) in allowed_types):
return issues
# Change ints to BitVec
if type(op0) is int:
op0 = symbol_factory.BitVecVal(op0, 256)
if type(op1) is int:
op1 = symbol_factory.BitVecVal(op1, 256)
# Formulate expression
# FIXME: handle exponentiation
if instruction["opcode"] == "ADD":
operator = "add"
expr = op0 + op1
constraint = Not(BVAddNoOverflow(op0, op1, signed=False))
else:
operator = "multiply"
expr = op1 * op0
constraint = Not(BVMulNoOverflow(op0, op1, signed=False))
# Check satisfiable # Check satisfiable
model = self._try_constraints(node.constraints, [constraint]) model = self._try_constraints(state.node.constraints, [c])
if model is None: if model is None:
log.debug("[INTEGER_OVERFLOW] no model found") return
return issues
annotation = OverUnderflowAnnotation(state, "subtraction", c)
op0.annotate(annotation)
# Build issue @staticmethod
def _make_bitvec_if_not(stack, index):
value = stack[index]
if isinstance(value, BitVec):
return value
stack[index] = symbol_factory.BitVecVal(value, 256)
return stack[index]
def _handle_sstore(self, state):
stack = state.mstate.stack
value = stack[-2]
if not isinstance(value, Expression):
return
for annotation in value.annotations:
if not isinstance(annotation, OverUnderflowAnnotation):
continue
title = (
"Integer Underflow"
if annotation.operator == "subtraction"
else "Integer Overflow"
)
ostate = annotation.overflowing_state
node = ostate.node
issue = Issue( issue = Issue(
contract=node.contract_name, contract=node.contract_name,
function_name=node.function_name, function_name=node.function_name,
address=instruction["address"], address=ostate.get_current_instruction()["address"],
swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW, swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW,
bytecode=state.environment.code.bytecode, bytecode=ostate.environment.code.bytecode,
title="Integer Overflow", title=title,
_type="Warning", _type="Warning",
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
) )
issue.description = "This binary {} operation can result in integer overflow.\n".format( issue.description = "This binary {} operation can result in {}.\n".format(
operator annotation.operator, title.lower()
) )
try: try:
issue.debug = str( issue.debug = str(
solver.get_transaction_sequence(state, node.constraints + [constraint]) solver.get_transaction_sequence(
state, node.constraints + [annotation.constraint]
) )
except UnsatError:
return issues
issues.append(issue)
return issues
def _verify_integer_overflow(
self, statespace, node, expr, state, model, constraint, op0, op1
):
"""Verifies existence of integer overflow.
:param statespace:
:param node:
:param expr:
:param state:
:param model:
:param constraint:
:param op0:
:param op1:
:return:
"""
# If we get to this point then there has been an integer overflow
# Find out if the overflowed value is actually used
interesting_usages = self._search_children(
statespace,
node,
expr,
constraint=[constraint],
index=node.states.index(state),
) )
# Stop if it isn't
if len(interesting_usages) == 0:
return False
return self._try_constraints(node.constraints, [Not(constraint)]) is not None
@staticmethod
def _try_constraints(constraints, new_constraints):
"""Tries new constraints.
:return Model if satisfiable otherwise None
"""
try:
model = solver.get_model(constraints + new_constraints)
return model
except UnsatError: except UnsatError:
return None return
self._issues.append(issue)
def _check_integer_underflow(self, statespace, state, node):
"""Checks for integer underflow.
:param statespace:
:param state: state from node to examine
:param node: node to examine
:return: found issue
"""
issues = []
instruction = state.get_current_instruction()
if instruction["opcode"] == "SUB":
def _handle_jumpi(self, state):
stack = state.mstate.stack stack = state.mstate.stack
value = stack[-2]
op0 = stack[-1] for annotation in value.annotations:
op1 = stack[-2] if not isinstance(annotation, OverUnderflowAnnotation):
continue
constraints = copy.deepcopy(node.constraints) ostate = annotation.overflowing_state
node = ostate.node
if type(op0) == int and type(op1) == int:
return []
log.debug(
"[INTEGER_UNDERFLOW] Checking SUB {0}, {1} at address {2}".format(
str(op0), str(op1), str(instruction["address"])
)
)
allowed_types = [int, BitVec]
if type(op0) in allowed_types and type(op1) in allowed_types:
constraints.append(Not(BVSubNoUnderflow(op0, op1, signed=False)))
try:
model = solver.get_model(constraints)
# If we get to this point then there has been an integer overflow
# Find out if the overflowed value is actually used
interesting_usages = self._search_children(
statespace, node, (op0 - op1), index=node.states.index(state)
)
# Stop if it isn't
if len(interesting_usages) == 0:
return issues
issue = Issue( issue = Issue(
contract=node.contract_name, contract=node.contract_name,
function_name=node.function_name, function_name=node.function_name,
address=instruction["address"], address=ostate.get_current_instruction()["address"],
swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW, swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW,
bytecode=state.environment.code.bytecode, bytecode=ostate.environment.code.bytecode,
title="Integer Underflow", title="Integer Overflow",
_type="Warning", _type="Warning",
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
) )
issue.description = ( issue.description = "This binary {} operation can result in integer overflow.\n".format(
"The subtraction can result in an integer underflow.\n" annotation.operator
) )
try:
issue.debug = str( issue.debug = str(
solver.get_transaction_sequence(state, node.constraints) solver.get_transaction_sequence(
state, node.constraints + [annotation.constraint]
)
) )
issues.append(issue)
except UnsatError: except UnsatError:
log.debug("[INTEGER_UNDERFLOW] no model found") return
return issues self._issues.append(issue)
def _check_usage(self, state, taint_result):
"""Delegates checks to _check_{instruction_name}()
:param state:
:param taint_result:
:return:
"""
opcode = state.get_current_instruction()["opcode"]
if opcode == "JUMPI":
if self._check_jumpi(state, taint_result):
return [state]
elif opcode == "SSTORE":
if self._check_sstore(state, taint_result):
return [state]
return []
@staticmethod @staticmethod
def _check_jumpi(state, taint_result): def _try_constraints(constraints, new_constraints):
"""Check if conditional jump is dependent on the result of expression. """Tries new constraints.
:param state:
:param taint_result:
:return:
"""
assert state.get_current_instruction()["opcode"] == "JUMPI"
return taint_result.check(state, -2)
@staticmethod
def _check_sstore(state, taint_result):
"""Check if store operation is dependent on the result of expression.
:param state: :return Model if satisfiable otherwise None
:param taint_result:
:return:
"""
assert state.get_current_instruction()["opcode"] == "SSTORE"
return taint_result.check(state, -2)
def _search_children(
self,
statespace,
node,
expression,
taint_result=None,
constraint=None,
index=0,
depth=0,
max_depth=64,
):
"""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
:param expression: Expression to look for
:param taint_result: Result of taint analysis
:param constraint:
:param index: Current state index node.states[index] == current_state
:param depth: Current depth level
:param max_depth: Max depth to explore
:return: List of states that match the opcodes and are dependent on expression
""" """
if constraint is None: try:
constraint = [] return solver.get_model(constraints + new_constraints)
except UnsatError:
log.debug("SEARCHING NODE for usage of an overflowed variable %d", node.uid) return None
if taint_result is None:
state = node.states[index]
taint_stack = [False for _ in state.mstate.stack]
taint_stack[-1] = True
taint_result = TaintRunner.execute(
statespace, node, state, initial_stack=taint_stack
)
results = []
if depth >= max_depth:
return []
# Explore current node from index
for j in range(index, len(node.states)):
current_state = node.states[j]
current_instruction = current_state.get_current_instruction()
if current_instruction["opcode"] in ("JUMPI", "SSTORE"):
element = self._check_usage(current_state, taint_result)
if len(element) < 1:
continue
results += element
# Recursively search children
children = [
statespace.nodes[edge.node_to]
for edge in statespace.edges
if edge.node_from == node.uid
# and _try_constraints(statespace.nodes[edge.node_to].constraints, constraint) is not None
]
for child in children:
results += self._search_children(
statespace,
child,
expression,
taint_result,
depth=depth + 1,
max_depth=max_depth,
)
return results
detector = IntegerOverflowUnderflowModule() detector = IntegerOverflowUnderflowModule()

@ -1,9 +1,26 @@
"""This module contains the detection code to find multiple sends occurring in """This module contains the detection code to find multiple sends occurring in
a single transaction.""" a single transaction."""
from copy import copy
from mythril.analysis.report import Issue from mythril.analysis.report import Issue
from mythril.analysis.swc_data import MULTIPLE_SENDS from mythril.analysis.swc_data import MULTIPLE_SENDS
from mythril.analysis.modules.base import DetectionModule from mythril.analysis.modules.base import DetectionModule
from mythril.laser.ethereum.cfg import JumpType from mythril.laser.ethereum.state.annotation import StateAnnotation
from mythril.laser.ethereum.state.global_state import GlobalState
import logging
from mythril.analysis.call_helpers import get_call_from_state
log = logging.getLogger(__name__)
class MultipleSendsAnnotation(StateAnnotation):
def __init__(self):
self.calls = []
def __copy__(self):
result = MultipleSendsAnnotation()
result.calls = copy(self.calls)
return result
class MultipleSendsModule(DetectionModule): class MultipleSendsModule(DetectionModule):
@ -14,103 +31,77 @@ class MultipleSendsModule(DetectionModule):
super().__init__( super().__init__(
name="Multiple Sends", name="Multiple Sends",
swc_id=MULTIPLE_SENDS, swc_id=MULTIPLE_SENDS,
hooks=["CALL", "DELEGATECALL", "STATICCALL", "CALLCODE"],
description="Check for multiple sends in a single transaction", description="Check for multiple sends in a single transaction",
entrypoint="callback",
pre_hooks=[
"CALL",
"DELEGATECALL",
"STATICCALL",
"CALLCODE",
"RETURN",
"STOP",
],
) )
self._issues = []
def execute(self, statespace): def execute(self, state: GlobalState):
""" """
:param statespace: :param state:
:return: :return:
""" """
issues = [] self._issues.extend(_analyze_state(state))
return self.issues
for call in statespace.calls:
findings = [] @property
# explore state def issues(self):
findings += self._explore_states(call, statespace) return self._issues
# explore nodes
findings += self._explore_nodes(call, statespace)
def _analyze_state(state: GlobalState):
if len(findings) > 0: """
node = call.node :param state: the current state
instruction = call.state.get_current_instruction() :return: returns the issues for that corresponding state
"""
node = state.node
instruction = state.get_current_instruction()
annotations = [a for a in state.get_annotations(MultipleSendsAnnotation)]
if len(annotations) == 0:
log.debug("Creating annotation for state")
state.annotate(MultipleSendsAnnotation())
annotations = [a for a in state.get_annotations(MultipleSendsAnnotation)]
calls = annotations[0].calls
if instruction["opcode"] in ["CALL", "DELEGATECALL", "STATICCALL", "CALLCODE"]:
call = get_call_from_state(state)
if call:
calls += [call]
else: # RETURN or STOP
if len(calls) > 1:
issue = Issue( issue = Issue(
contract=node.contract_name, contract=node.contract_name,
function_name=node.function_name, function_name=node.function_name,
address=instruction["address"], address=instruction["address"],
swc_id=MULTIPLE_SENDS, swc_id=MULTIPLE_SENDS,
bytecode=call.state.environment.code.bytecode, bytecode=state.environment.code.bytecode,
title="Multiple Calls", title="Multiple Calls",
_type="Informational", _type="Informational",
gas_used=( gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
call.state.mstate.min_gas_used,
call.state.mstate.max_gas_used,
),
) )
issue.description = ( issue.description = (
"Multiple sends are executed in a single transaction. " "Multiple sends are executed in a single transaction. "
"Try to isolate each external call into its own transaction," "Try to isolate each external call into its own transaction,"
" as external calls can fail accidentally or deliberately.\nConsecutive calls: \n" " as external calls can fail accidentally or deliberately.\nConsecutive calls: \n"
) )
for call in calls:
for finding in findings:
issue.description += "Call at address: {}\n".format( issue.description += "Call at address: {}\n".format(
finding.state.get_current_instruction()["address"] call.state.get_current_instruction()["address"]
) )
return [issue]
issues.append(issue) return []
return issues
def _explore_nodes(self, call, statespace):
"""
:param call:
:param statespace:
:return:
"""
children = self._child_nodes(statespace, call.node)
sending_children = list(filter(lambda c: c.node in children, statespace.calls))
return sending_children
@staticmethod
def _explore_states(call, statespace):
"""
:param call:
:param statespace:
:return:
"""
other_calls = list(
filter(
lambda other: other.node == call.node
and other.state_index > call.state_index,
statespace.calls,
)
)
return other_calls
def _child_nodes(self, statespace, node):
"""
:param statespace:
:param node:
:return:
"""
result = []
children = [
statespace.nodes[edge.node_to]
for edge in statespace.edges
if edge.node_from == node.uid and edge.type != JumpType.Transaction
]
for child in children:
result.append(child)
result += self._child_nodes(statespace, child)
return result
detector = MultipleSendsModule() detector = MultipleSendsModule()

@ -1,11 +1,10 @@
import logging
from mythril.analysis import solver from mythril.analysis import solver
from mythril.analysis.modules.base import DetectionModule
from mythril.analysis.report import Issue from mythril.analysis.report import Issue
from mythril.analysis.swc_data import UNPROTECTED_SELFDESTRUCT from mythril.analysis.swc_data import UNPROTECTED_SELFDESTRUCT
from mythril.exceptions import UnsatError from mythril.exceptions import UnsatError
from mythril.analysis.modules.base import DetectionModule
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -67,9 +66,9 @@ class SuicideModule(DetectionModule):
super().__init__( super().__init__(
name="Unprotected Suicide", name="Unprotected Suicide",
swc_id=UNPROTECTED_SELFDESTRUCT, swc_id=UNPROTECTED_SELFDESTRUCT,
hooks=["SUICIDE"],
description=DESCRIPTION, description=DESCRIPTION,
entrypoint="callback", entrypoint="callback",
pre_hooks=["SUICIDE"],
) )
self._issues = [] self._issues = []

@ -21,7 +21,6 @@ class TxOrderDependenceModule(DetectionModule):
super().__init__( super().__init__(
name="Transaction Order Dependence", name="Transaction Order Dependence",
swc_id=TX_ORDER_DEPENDENCE, swc_id=TX_ORDER_DEPENDENCE,
hooks=[],
description=( description=(
"This module finds the existance of transaction order dependence " "This module finds the existance of transaction order dependence "
"vulnerabilities. The following webpage contains an extensive description " "vulnerabilities. The following webpage contains an extensive description "

@ -1,16 +1,30 @@
"""This module contains detection code to find occurrences of calls whose """This module contains detection code to find occurrences of calls whose
return value remains unchecked.""" return value remains unchecked."""
from copy import copy
from mythril.analysis import solver
from mythril.analysis.report import Issue from mythril.analysis.report import Issue
from mythril.analysis.swc_data import UNCHECKED_RET_VAL from mythril.analysis.swc_data import UNCHECKED_RET_VAL
from mythril.analysis.modules.base import DetectionModule from mythril.analysis.modules.base import DetectionModule
from mythril.exceptions import UnsatError
from mythril.laser.ethereum.state.annotation import StateAnnotation
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum.svm import NodeFlags
import logging import logging
import re
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class UncheckedRetvalAnnotation(StateAnnotation):
def __init__(self):
self.retvals = []
def __copy__(self):
result = UncheckedRetvalAnnotation()
result.retvals = copy(self.retvals)
return result
class UncheckedRetvalModule(DetectionModule): class UncheckedRetvalModule(DetectionModule):
"""A detection module to test whether CALL return value is checked.""" """A detection module to test whether CALL return value is checked."""
@ -18,7 +32,6 @@ class UncheckedRetvalModule(DetectionModule):
super().__init__( super().__init__(
name="Unchecked Return Value", name="Unchecked Return Value",
swc_id=UNCHECKED_RET_VAL, swc_id=UNCHECKED_RET_VAL,
hooks=[],
description=( description=(
"Test whether CALL return value is checked. " "Test whether CALL return value is checked. "
"For direct calls, the Solidity compiler auto-generates this check. E.g.:\n" "For direct calls, the Solidity compiler auto-generates this check. E.g.:\n"
@ -28,110 +41,71 @@ class UncheckedRetvalModule(DetectionModule):
"For low-level-calls this check is omitted. E.g.:\n" "For low-level-calls this check is omitted. E.g.:\n"
' c.call.value(0)(bytes4(sha3("ping(uint256)")),1);' ' c.call.value(0)(bytes4(sha3("ping(uint256)")),1);'
), ),
entrypoint="callback",
pre_hooks=["STOP", "RETURN"],
post_hooks=["CALL", "DELEGATECALL", "STATICCALL", "CALLCODE"],
) )
self._issues = []
def execute(self, statespace): def execute(self, state: GlobalState) -> list:
""" """
:param statespace: :param state:
:return: :return:
""" """
log.debug("Executing module: UNCHECKED_RETVAL") self._issues.extend(_analyze_state(state))
return self.issues
issues = []
for k in statespace.nodes:
node = statespace.nodes[k]
if NodeFlags.CALL_RETURN in node.flags:
retval_checked = False
for state in node.states:
instr = state.get_current_instruction()
if instr["opcode"] == "ISZERO" and re.search(
r"retval", str(state.mstate.stack[-1])
):
retval_checked = True
break
if not retval_checked:
address = state.get_current_instruction()["address"]
issue = Issue(
contract=node.contract_name,
function_name=node.function_name,
address=address,
bytecode=state.environment.code.bytecode,
title="Unchecked CALL return value",
swc_id=UNCHECKED_RET_VAL,
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
)
issue.description = ( @property
"The return value of an external call is not checked. " def issues(self):
"Note that execution continue even if the called contract throws." return self._issues
)
issues.append(issue)
else:
n_states = len(node.states)
for idx in range( def _analyze_state(state: GlobalState) -> list:
0, n_states - 1 instruction = state.get_current_instruction()
): # Ignore CALLs at last position in a node node = state.node
state = node.states[idx] annotations = [a for a in state.get_annotations(UncheckedRetvalAnnotation)]
instr = state.get_current_instruction() if len(annotations) == 0:
state.annotate(UncheckedRetvalAnnotation())
annotations = [a for a in state.get_annotations(UncheckedRetvalAnnotation)]
if instr["opcode"] == "CALL": retvals = annotations[0].retvals
retval_checked = False
for _idx in range(idx, idx + 10):
if instruction["opcode"] in ("STOP", "RETURN"):
issues = []
for retval in retvals:
try: try:
_state = node.states[_idx] model = solver.get_model(node.constraints + [retval["retval"] == 0])
_instr = _state.get_current_instruction() except UnsatError:
continue
if _instr["opcode"] == "ISZERO" and re.search(
r"retval", str(_state.mstate.stack[-1])
):
retval_checked = True
break
except IndexError:
break
if not retval_checked:
address = instr["address"]
issue = Issue( issue = Issue(
contract=node.contract_name, contract=node.contract_name,
function_name=node.function_name, function_name=node.function_name,
address=retval["address"],
bytecode=state.environment.code.bytecode, bytecode=state.environment.code.bytecode,
address=address,
title="Unchecked CALL return value", title="Unchecked CALL return value",
swc_id=UNCHECKED_RET_VAL, swc_id=UNCHECKED_RET_VAL,
gas_used=( gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
state.mstate.min_gas_used,
state.mstate.max_gas_used,
),
) )
issue.description = ( issue.description = (
"The return value of an external call is not checked. " "The return value of an external call is not checked. "
"Note that execution continue even if the called contract throws." "Note that execution continue even if the called contract throws."
) )
issues.append(issue) issues.append(issue)
return issues return issues
else:
log.debug("End of call, extracting retval")
assert state.environment.code.instruction_list[state.mstate.pc - 1][
"opcode"
] in ["CALL", "DELEGATECALL", "STATICCALL", "CALLCODE"]
retval = state.mstate.stack[-1]
retvals.append({"address": state.instruction["address"] - 1, "retval": retval})
return []
detector = UncheckedRetvalModule() detector = UncheckedRetvalModule()

@ -1,13 +1,11 @@
"""This module contains functionality for hooking in detection modules and """This module contains functionality for hooking in detection modules and
executing them.""" executing them."""
import importlib.util
import logging
import pkgutil
from collections import defaultdict from collections import defaultdict
from ethereum.opcodes import opcodes from ethereum.opcodes import opcodes
from mythril.analysis import modules from mythril.analysis import modules
import pkgutil
import importlib.util
import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -21,16 +19,16 @@ def reset_callback_modules():
module.detector._issues = [] module.detector._issues = []
def get_detection_module_hooks(modules): def get_detection_module_hooks(modules, hook_type="pre"):
"""
:param modules:
:return:
"""
hook_dict = defaultdict(list) hook_dict = defaultdict(list)
_modules = get_detection_modules(entrypoint="callback", include_modules=modules) _modules = get_detection_modules(entrypoint="callback", include_modules=modules)
for module in _modules: for module in _modules:
for op_code in map(lambda x: x.upper(), module.detector.hooks): hooks = (
module.detector.pre_hooks
if hook_type == "pre"
else module.detector.post_hooks
)
for op_code in map(lambda x: x.upper(), hooks):
if op_code in OPCODE_LIST: if op_code in OPCODE_LIST:
hook_dict[op_code].append(module.detector.execute) hook_dict[op_code].append(module.detector.execute)
elif op_code.endswith("*"): elif op_code.endswith("*"):

@ -1,5 +1,7 @@
"""This module contains analysis module helpers to solve path constraints.""" """This module contains analysis module helpers to solve path constraints."""
from z3 import sat, unknown, FuncInterp from z3 import sat, unknown, FuncInterp
import z3
from mythril.laser.smt import simplify, UGE, Optimize, symbol_factory from mythril.laser.smt import simplify, UGE, Optimize, symbol_factory
from mythril.exceptions import UnsatError from mythril.exceptions import UnsatError
from mythril.laser.ethereum.transaction.transaction_models import ( from mythril.laser.ethereum.transaction.transaction_models import (
@ -59,7 +61,7 @@ def pretty_print_model(model):
try: try:
condition = "0x%x" % model[d].as_long() condition = "0x%x" % model[d].as_long()
except: except:
condition = str(simplify(model[d])) condition = str(z3.simplify(model[d]))
ret += "%s: %s\n" % (d.name(), condition) ret += "%s: %s\n" % (d.name(), condition)

@ -76,7 +76,12 @@ class SymExecWrapper:
transaction_count=transaction_count, transaction_count=transaction_count,
) )
self.laser.register_hooks( self.laser.register_hooks(
hook_type="pre", hook_dict=get_detection_module_hooks(modules) hook_type="pre",
hook_dict=get_detection_module_hooks(modules, hook_type="pre"),
)
self.laser.register_hooks(
hook_type="post",
hook_dict=get_detection_module_hooks(modules, hook_type="post"),
) )
if isinstance(contract, SolidityContract): if isinstance(contract, SolidityContract):

@ -3,19 +3,22 @@ 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
from typing import Union
from mythril.laser.ethereum import natives
from mythril.laser.ethereum.gas import OPCODE_GAS
from mythril.laser.smt import simplify, Expression, symbol_factory
import mythril.laser.ethereum.util as util 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 (
CalldataType, CalldataType,
ConcreteCalldata,
SymbolicCalldata, SymbolicCalldata,
ConcreteCalldata,
BaseCalldata,
) )
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.smt import Expression, simplify, 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
@ -194,3 +197,47 @@ def get_call_data(
call_data = SymbolicCalldata("{}_internalcall".format(transaction_id)) call_data = SymbolicCalldata("{}_internalcall".format(transaction_id))
return call_data, call_data_type return call_data, call_data_type
def native_call(
global_state: GlobalState,
callee_address: str,
call_data: BaseCalldata,
memory_out_offset: Union[int, Expression],
memory_out_size: Union[int, Expression],
) -> Union[List[GlobalState], None]:
if not 0 < int(callee_address, 16) < 5:
return None
log.debug("Native contract called: " + callee_address)
try:
mem_out_start = util.get_concrete_int(memory_out_offset)
mem_out_sz = util.get_concrete_int(memory_out_size)
except TypeError:
log.debug("CALL with symbolic start or offset not supported")
return [global_state]
contract_list = ["ecrecover", "sha256", "ripemd160", "identity"]
call_address_int = int(callee_address, 16)
native_gas_min, native_gas_max = OPCODE_GAS["NATIVE_COST"](
global_state.mstate.calculate_extension_size(mem_out_start, mem_out_sz),
contract_list[call_address_int - 1],
)
global_state.mstate.min_gas_used += native_gas_min
global_state.mstate.max_gas_used += native_gas_max
global_state.mstate.mem_extend(mem_out_start, mem_out_sz)
try:
data = natives.native_contracts(call_address_int, call_data)
except natives.NativeContractException:
for i in range(mem_out_sz):
global_state.mstate.memory[mem_out_start + i] = global_state.new_bitvec(
contract_list[call_address_int - 1] + "(" + str(call_data) + ")", 8
)
return [global_state]
for i in range(
min(len(data), mem_out_sz)
): # If more data is used then it's chopped off
global_state.mstate.memory[mem_out_start + i] = data[i]
# TODO: maybe use BitVec here constrained to 1
return [global_state]

@ -2,31 +2,12 @@
transitions between them.""" transitions between them."""
import binascii import binascii
import logging import logging
from copy import copy, deepcopy from copy import copy, deepcopy
from typing import Callable, List, Union from typing import Callable, List, Union
from ethereum import utils from ethereum import utils
import mythril.laser.ethereum.natives as natives
import mythril.laser.ethereum.util as helper
from mythril.laser.ethereum import util
from mythril.laser.ethereum.call import get_call_parameters
from mythril.laser.ethereum.evm_exceptions import (
VmException,
StackUnderflowException,
InvalidJumpDestination,
InvalidInstruction,
OutOfGasException,
)
from mythril.laser.ethereum.gas import OPCODE_GAS
from mythril.laser.ethereum.keccak import KeccakFunctionManager
from mythril.laser.ethereum.state.calldata import CalldataType
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum.transaction import (
MessageCallTransaction,
TransactionStartSignal,
ContractCreationTransaction,
)
from mythril.laser.smt import ( from mythril.laser.smt import (
Extract, Extract,
Expression, Expression,
@ -46,6 +27,26 @@ from mythril.laser.smt import (
Not, Not,
) )
from mythril.laser.smt import symbol_factory from mythril.laser.smt import symbol_factory
import mythril.laser.ethereum.util as helper
from mythril.laser.ethereum import util
from mythril.laser.ethereum.call import get_call_parameters, native_call
from mythril.laser.ethereum.evm_exceptions import (
VmException,
StackUnderflowException,
InvalidJumpDestination,
InvalidInstruction,
OutOfGasException,
)
from mythril.laser.ethereum.gas import OPCODE_GAS
from mythril.laser.ethereum.keccak import KeccakFunctionManager
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum.transaction import (
MessageCallTransaction,
TransactionStartSignal,
ContractCreationTransaction,
)
from mythril.support.loader import DynLoader from mythril.support.loader import DynLoader
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -634,8 +635,12 @@ class Instruction:
state = global_state.mstate state = global_state.mstate
val = state.stack.pop() val = state.stack.pop()
exp = (val == False) if isinstance(val, Bool) else val == 0 exp = Not(val) if isinstance(val, Bool) else val == 0
state.stack.append(exp)
exp = If(
exp, symbol_factory.BitVecVal(1, 256), symbol_factory.BitVecVal(0, 256)
)
state.stack.append(simplify(exp))
return [global_state] return [global_state]
@ -1327,7 +1332,7 @@ class Instruction:
keccak_keys = filter(keccak_function_manager.is_keccak, storage_keys) keccak_keys = filter(keccak_function_manager.is_keccak, storage_keys)
results = [] results = []
new = False new = symbol_factory.Bool(False)
for keccak_key in keccak_keys: for keccak_key in keccak_keys:
key_argument = keccak_function_manager.get_argument(keccak_key) key_argument = keccak_function_manager.get_argument(keccak_key)
@ -1458,9 +1463,9 @@ class Instruction:
negated = ( negated = (
simplify(Not(condition)) if isinstance(condition, Bool) else condition == 0 simplify(Not(condition)) if isinstance(condition, Bool) else condition == 0
) )
negated.simplify()
if (type(negated) == bool and negated) or ( if (type(negated) == bool and negated) or (
isinstance(condition, Bool) and not is_false(negated) isinstance(negated, Bool) and not is_false(negated)
): ):
new_state = copy(global_state) new_state = copy(global_state)
# add JUMPI gas cost # add JUMPI gas cost
@ -1486,6 +1491,7 @@ class Instruction:
instr = disassembly.instruction_list[index] instr = disassembly.instruction_list[index]
condi = simplify(condition) if isinstance(condition, Bool) else condition != 0 condi = simplify(condition) if isinstance(condition, Bool) else condition != 0
condi.simplify()
if instr["opcode"] == "JUMPDEST": if instr["opcode"] == "JUMPDEST":
if (type(condi) == bool and condi) or ( if (type(condi) == bool and condi) or (
isinstance(condi, Bool) and not is_false(condi) isinstance(condi, Bool) and not is_false(condi)
@ -1690,49 +1696,11 @@ class Instruction:
global_state.new_bitvec("retval_" + str(instr["address"]), 256) global_state.new_bitvec("retval_" + str(instr["address"]), 256)
) )
if 0 < int(callee_address, 16) < 5: native_result = native_call(
log.debug("Native contract called: " + callee_address) global_state, callee_address, call_data, memory_out_offset, memory_out_size
if call_data == [] and call_data_type == CalldataType.SYMBOLIC:
log.debug("CALL with symbolic data not supported")
return [global_state]
try:
mem_out_start = helper.get_concrete_int(memory_out_offset)
mem_out_sz = helper.get_concrete_int(memory_out_size)
except TypeError:
log.debug("CALL with symbolic start or offset not supported")
return [global_state]
contract_list = ["ecrecover", "sha256", "ripemd160", "identity"]
call_address_int = int(callee_address, 16)
native_gas_min, native_gas_max = OPCODE_GAS["NATIVE_COST"](
global_state.mstate.calculate_extension_size(mem_out_start, mem_out_sz),
contract_list[call_address_int - 1],
) )
global_state.mstate.min_gas_used += native_gas_min if native_result:
global_state.mstate.max_gas_used += native_gas_max return native_result
global_state.mstate.mem_extend(mem_out_start, mem_out_sz)
try:
data = natives.native_contracts(call_address_int, call_data)
except natives.NativeContractException:
for i in range(mem_out_sz):
global_state.mstate.memory[
mem_out_start + i
] = global_state.new_bitvec(
contract_list[call_address_int - 1]
+ "("
+ str(call_data)
+ ")",
8,
)
return [global_state]
for i in range(
min(len(data), mem_out_sz)
): # If more data is used then it's chopped off
global_state.mstate.memory[mem_out_start + i] = data[i]
# TODO: maybe use BitVec here constrained to 1
return [global_state]
transaction = MessageCallTransaction( transaction = MessageCallTransaction(
world_state=global_state.world_state, world_state=global_state.world_state,
@ -2033,7 +2001,28 @@ class Instruction:
""" """
# TODO: implement me # TODO: implement me
instr = global_state.get_current_instruction() instr = global_state.get_current_instruction()
try:
callee_address, callee_account, call_data, value, call_data_type, gas, memory_out_offset, memory_out_size = get_call_parameters(
global_state, self.dynamic_loader
)
except ValueError as e:
log.debug(
"Could not determine required parameters for call, putting fresh symbol on the stack. \n{}".format(
e
)
)
global_state.mstate.stack.append( global_state.mstate.stack.append(
global_state.new_bitvec("retval_" + str(instr["address"]), 256) global_state.new_bitvec("retval_" + str(instr["address"]), 256)
) )
return [global_state] return [global_state]
global_state.mstate.stack.append(
global_state.new_bitvec("retval_" + str(instr["address"]), 256)
)
native_result = native_call(
global_state, callee_address, call_data, memory_out_offset, memory_out_size
)
if native_result:
return native_result
return [global_state]

@ -34,11 +34,14 @@ class Storage:
and (self.dynld and self.dynld.storage_loading) and (self.dynld and self.dynld.storage_loading)
): ):
try: try:
self._storage[item] = int( self._storage[item] = symbol_factory.BitVecVal(
int(
self.dynld.read_storage( self.dynld.read_storage(
contract_address=self.address, index=int(item) contract_address=self.address, index=int(item)
), ),
16, 16,
),
256,
) )
return self._storage[item] return self._storage[item]
except ValueError: except ValueError:

@ -82,8 +82,8 @@ class MachineStack(list):
class MachineState: class MachineState:
"""MachineState represents current machine state also referenced to as """MachineState represents current machine state also referenced to as \mu.
\mu.""" """
def __init__( def __init__(
self, self,

@ -26,6 +26,16 @@ class SymbolFactory:
"""A symbol factory provides a default interface for all the components of """A symbol factory provides a default interface for all the components of
mythril to create symbols.""" mythril to create symbols."""
@staticmethod
def Bool(value: bool, annotations=None):
"""Creates a Bool with concrete value.
:param value: The boolean value
:param annotations: The annotations to initialize the bool with
:return: The freshly created Bool()
"""
raise NotImplementedError
@staticmethod @staticmethod
def BitVecVal(value: int, size: int, annotations=None): 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.
@ -53,6 +63,17 @@ class _SmtSymbolFactory(SymbolFactory):
"""An implementation of a SymbolFactory that creates symbols using the """An implementation of a SymbolFactory that creates symbols using the
classes in: mythril.laser.smt.""" classes in: mythril.laser.smt."""
@staticmethod
def Bool(value: bool, annotations=None):
"""Creates a Bool with concrete value.
:param value: The boolean value
:param annotations: The annotations to initialize the bool with
:return: The freshly created Bool()
"""
raw = z3.Bool(value)
return Bool(raw, annotations)
@staticmethod @staticmethod
def BitVecVal(value: int, size: int, annotations=None): 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."""
@ -70,6 +91,11 @@ class _Z3SymbolFactory(SymbolFactory):
"""An implementation of a SymbolFactory that directly returns z3 """An implementation of a SymbolFactory that directly returns z3
symbols.""" symbols."""
@staticmethod
def Bool(value: bool, annotations=None):
"""Creates a new bit vector with a concrete value."""
return z3.Bool(value)
@staticmethod @staticmethod
def BitVecVal(value: int, size: int, annotations=None): 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."""

@ -28,6 +28,7 @@ class GraphTest(BaseTestCase):
address=(util.get_indexed_address(0)), address=(util.get_indexed_address(0)),
strategy="dfs", strategy="dfs",
transaction_count=1, transaction_count=1,
execution_timeout=5,
) )
html = generate_graph(sym) html = generate_graph(sym)

@ -14,12 +14,12 @@ IDENTITY_TEST = [(0, False) for _ in range(2)]
# These are Random numbers to check whether the 'if condition' is entered or not # These are Random numbers to check whether the 'if condition' is entered or not
# (True means entered) # (True means entered)
SHA256_TEST[0] = (hex(5555555555555555), True) SHA256_TEST[0] = (hex(5555555555555555), True)
SHA256_TEST[1] = (hex(323232325445454546), True) SHA256_TEST[1] = (hex(323232325445454546), False)
SHA256_TEST[2] = (hex(34756834765834658), True) SHA256_TEST[2] = (hex(34756834765834658), True)
SHA256_TEST[3] = (hex(8756476956956795876987), True) SHA256_TEST[3] = (hex(8756476956956795876987), False)
RIPEMD160_TEST[0] = (hex(999999999999999999993), True) RIPEMD160_TEST[0] = (hex(999999999999999999993), True)
RIPEMD160_TEST[1] = (hex(1111111111112), True) RIPEMD160_TEST[1] = (hex(1111111111112), False)
ECRECOVER_TEST[0] = (hex(674837568743979857398564869), True) ECRECOVER_TEST[0] = (hex(674837568743979857398564869), True)
ECRECOVER_TEST[1] = (hex(3487683476979311), False) ECRECOVER_TEST[1] = (hex(3487683476979311), False)

@ -1 +1,102 @@
{"error": null, "issues": [{"address": 661, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", "function": "thisisfine()", "max_gas_used": 1254, "min_gas_used": 643, "swc-id": "107", "title": "External call", "type": "Informational"}, {"address": 666, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "thisisfine()", "max_gas_used": 35963, "min_gas_used": 1352, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 779, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", "function": "callstoredaddress()", "max_gas_used": 1298, "min_gas_used": 687, "swc-id": "107", "title": "External call", "type": "Informational"}, {"address": 784, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "callstoredaddress()", "max_gas_used": 36007, "min_gas_used": 1396, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 858, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", "function": "reentrancy()", "max_gas_used": 1320, "min_gas_used": 709, "swc-id": "107", "title": "External call", "type": "Informational"}, {"address": 871, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "reentrancy()", "max_gas_used": 61043, "min_gas_used": 6432, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 912, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state.", "function": "calluseraddress(address)", "max_gas_used": 616, "min_gas_used": 335, "swc-id": "107", "title": "External call to user-supplied address", "type": "Warning"}, {"address": 918, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "calluseraddress(address)", "max_gas_used": 35327, "min_gas_used": 1046, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true} {
"error": null,
"issues": [
{
"address": 661,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.",
"function": "thisisfine()",
"max_gas_used": 1254,
"min_gas_used": 643,
"swc-id": "107",
"title": "External call",
"type": "Informational"
},
{
"address": 661,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "thisisfine()",
"max_gas_used": 35972,
"min_gas_used": 1361,
"swc-id": "104",
"title": "Unchecked CALL return value",
"type": "Informational"
},
{
"address": 779,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.",
"function": "callstoredaddress()",
"max_gas_used": 1298,
"min_gas_used": 687,
"swc-id": "107",
"title": "External call",
"type": "Informational"
},
{
"address": 779,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "callstoredaddress()",
"max_gas_used": 36016,
"min_gas_used": 1405,
"swc-id": "104",
"title": "Unchecked CALL return value",
"type": "Informational"
},
{
"address": 858,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.",
"function": "reentrancy()",
"max_gas_used": 1320,
"min_gas_used": 709,
"swc-id": "107",
"title": "External call",
"type": "Informational"
},
{
"address": 858,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "reentrancy()",
"max_gas_used": 61052,
"min_gas_used": 6441,
"swc-id": "104",
"title": "Unchecked CALL return value",
"type": "Informational"
},
{
"address": 912,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state.",
"function": "calluseraddress(address)",
"max_gas_used": 616,
"min_gas_used": 335,
"swc-id": "107",
"title": "External call to user-supplied address",
"type": "Warning"
},
{
"address": 912,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "calluseraddress(address)",
"max_gas_used": 35336,
"min_gas_used": 1055,
"swc-id": "104",
"title": "Unchecked CALL return value",
"type": "Informational"
}
],
"success": true
}

@ -17,8 +17,8 @@ The contract executes a function call to an external address. Verify that the co
- Type: Informational - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `thisisfine()` - Function name: `thisisfine()`
- PC address: 666 - PC address: 661
- Estimated Gas Usage: 1352 - 35963 - Estimated Gas Usage: 1361 - 35972
### Description ### Description
@ -41,8 +41,8 @@ The contract executes a function call to an external address. Verify that the co
- Type: Informational - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `callstoredaddress()` - Function name: `callstoredaddress()`
- PC address: 784 - PC address: 779
- Estimated Gas Usage: 1396 - 36007 - Estimated Gas Usage: 1405 - 36016
### Description ### Description
@ -65,8 +65,8 @@ The contract executes a function call to an external address. Verify that the co
- Type: Informational - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `reentrancy()` - Function name: `reentrancy()`
- PC address: 871 - PC address: 858
- Estimated Gas Usage: 6432 - 61043 - Estimated Gas Usage: 6441 - 61052
### Description ### Description
@ -89,8 +89,8 @@ The contract executes a function call with high gas to a user-supplied address.
- Type: Informational - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `calluseraddress(address)` - Function name: `calluseraddress(address)`
- PC address: 918 - PC address: 912
- Estimated Gas Usage: 1046 - 35327 - Estimated Gas Usage: 1055 - 35336
### Description ### Description

@ -13,8 +13,8 @@ SWC ID: 104
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown
Function name: thisisfine() Function name: thisisfine()
PC address: 666 PC address: 661
Estimated Gas Usage: 1352 - 35963 Estimated Gas Usage: 1361 - 35972
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
-------------------- --------------------
@ -33,8 +33,8 @@ SWC ID: 104
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown
Function name: callstoredaddress() Function name: callstoredaddress()
PC address: 784 PC address: 779
Estimated Gas Usage: 1396 - 36007 Estimated Gas Usage: 1405 - 36016
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
-------------------- --------------------
@ -53,8 +53,8 @@ SWC ID: 104
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown
Function name: reentrancy() Function name: reentrancy()
PC address: 871 PC address: 858
Estimated Gas Usage: 6432 - 61043 Estimated Gas Usage: 6441 - 61052
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
-------------------- --------------------
@ -73,8 +73,8 @@ SWC ID: 104
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown
Function name: calluseraddress(address) Function name: calluseraddress(address)
PC address: 918 PC address: 912
Estimated Gas Usage: 1046 - 35327 Estimated Gas Usage: 1055 - 35336
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
-------------------- --------------------

@ -1,6 +1,18 @@
{ {
"error": null, "error": null,
"issues": [ "issues": [
{
"address": 618,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "_function_0x141f32ff",
"max_gas_used": 35865,
"min_gas_used": 1113,
"swc-id": "104",
"title": "Unchecked CALL return value",
"type": "Informational"
},
{ {
"address": 618, "address": 618,
"contract": "Unknown", "contract": "Unknown",
@ -14,25 +26,13 @@
"type": "Warning" "type": "Warning"
}, },
{ {
"address": 626, "address": 849,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "_function_0x141f32ff",
"max_gas_used": 35856,
"min_gas_used": 1104,
"swc-id": "104",
"title": "Unchecked CALL return value",
"type": "Informational"
},
{
"address": 857,
"contract": "Unknown", "contract": "Unknown",
"debug": "<DEBUG-DATA>", "debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "_function_0x9b58bc26", "function": "_function_0x9b58bc26",
"max_gas_used": 35913, "max_gas_used": 35922,
"min_gas_used": 1161, "min_gas_used": 1170,
"swc-id": "104", "swc-id": "104",
"title": "Unchecked CALL return value", "title": "Unchecked CALL return value",
"type": "Informational" "type": "Informational"
@ -50,13 +50,13 @@
"type": "Warning" "type": "Warning"
}, },
{ {
"address": 1046, "address": 1038,
"contract": "Unknown", "contract": "Unknown",
"debug": "<DEBUG-DATA>", "debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "_function_0xeea4c864", "function": "_function_0xeea4c864",
"max_gas_used": 35938, "max_gas_used": 35947,
"min_gas_used": 1186, "min_gas_used": 1195,
"swc-id": "104", "swc-id": "104",
"title": "Unchecked CALL return value", "title": "Unchecked CALL return value",
"type": "Informational" "type": "Informational"

@ -1,36 +1,36 @@
# Analysis results for test-filename.sol # Analysis results for test-filename.sol
## Use of callcode ## Unchecked CALL return value
- SWC ID: 111 - SWC ID: 104
- Type: Warning - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `_function_0x141f32ff` - Function name: `_function_0x141f32ff`
- PC address: 618 - PC address: 618
- Estimated Gas Usage: 389 - 1141 - Estimated Gas Usage: 1113 - 35865
### Description ### Description
The function `_function_0x141f32ff` uses callcode. Callcode does not persist sender or value over the call. Use delegatecall instead. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
## Unchecked CALL return value ## Use of callcode
- SWC ID: 104 - SWC ID: 111
- Type: Informational - Type: Warning
- Contract: Unknown - Contract: Unknown
- Function name: `_function_0x141f32ff` - Function name: `_function_0x141f32ff`
- PC address: 626 - PC address: 618
- Estimated Gas Usage: 1104 - 35856 - Estimated Gas Usage: 389 - 1141
### Description ### Description
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The function `_function_0x141f32ff` uses callcode. Callcode does not persist sender or value over the call. Use delegatecall instead.
## Unchecked CALL return value ## Unchecked CALL return value
- SWC ID: 104 - SWC ID: 104
- Type: Informational - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `_function_0x9b58bc26` - Function name: `_function_0x9b58bc26`
- PC address: 857 - PC address: 849
- Estimated Gas Usage: 1161 - 35913 - Estimated Gas Usage: 1170 - 35922
### Description ### Description
@ -53,8 +53,8 @@ The contract executes a function call with high gas to a user-supplied address.
- Type: Informational - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `_function_0xeea4c864` - Function name: `_function_0xeea4c864`
- PC address: 1046 - PC address: 1038
- Estimated Gas Usage: 1186 - 35938 - Estimated Gas Usage: 1195 - 35947
### Description ### Description

@ -1,3 +1,13 @@
==== Unchecked CALL return value ====
SWC ID: 104
Type: Informational
Contract: Unknown
Function name: _function_0x141f32ff
PC address: 618
Estimated Gas Usage: 1113 - 35865
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------
==== Use of callcode ==== ==== Use of callcode ====
SWC ID: 111 SWC ID: 111
Type: Warning Type: Warning
@ -8,23 +18,13 @@ Estimated Gas Usage: 389 - 1141
The function `_function_0x141f32ff` uses callcode. Callcode does not persist sender or value over the call. Use delegatecall instead. The function `_function_0x141f32ff` uses callcode. Callcode does not persist sender or value over the call. Use delegatecall instead.
-------------------- --------------------
==== Unchecked CALL return value ====
SWC ID: 104
Type: Informational
Contract: Unknown
Function name: _function_0x141f32ff
PC address: 626
Estimated Gas Usage: 1104 - 35856
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------
==== Unchecked CALL return value ==== ==== Unchecked CALL return value ====
SWC ID: 104 SWC ID: 104
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown
Function name: _function_0x9b58bc26 Function name: _function_0x9b58bc26
PC address: 857 PC address: 849
Estimated Gas Usage: 1161 - 35913 Estimated Gas Usage: 1170 - 35922
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
-------------------- --------------------
@ -43,8 +43,8 @@ SWC ID: 104
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown
Function name: _function_0xeea4c864 Function name: _function_0xeea4c864
PC address: 1046 PC address: 1038
Estimated Gas Usage: 1186 - 35938 Estimated Gas Usage: 1195 - 35947
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
-------------------- --------------------

@ -1,30 +1,42 @@
{ {
"error": null, "error":null,
"issues": [ "issues":[
{ {
"address": 567, "address":567,
"contract": "Unknown", "contract":"Unknown",
"debug": "<DEBUG-DATA>", "debug":"<DEBUG-DATA>",
"description": "The subtraction can result in an integer underflow.\n", "description":"This binary subtraction operation can result in integer overflow.\n",
"function": "sendeth(address,uint256)", "function":"sendeth(address,uint256)",
"max_gas_used": 1035, "max_gas_used":1053,
"min_gas_used": 750, "min_gas_used":768,
"swc-id": "101", "swc-id":"101",
"title": "Integer Underflow", "title":"Integer Overflow",
"type": "Warning" "type":"Warning"
}, },
{ {
"address": 649, "address":567,
"contract": "Unknown", "contract":"Unknown",
"debug": "<DEBUG-DATA>", "debug":"<DEBUG-DATA>",
"description": "The subtraction can result in an integer underflow.\n", "description":"This binary subtraction operation can result in integer underflow.\n",
"function": "sendeth(address,uint256)", "function":"sendeth(address,uint256)",
"max_gas_used": 1758, "max_gas_used":1774,
"min_gas_used": 1283, "min_gas_used":1299,
"swc-id": "101", "swc-id":"101",
"title": "Integer Underflow", "title":"Integer Underflow",
"type": "Warning" "type":"Warning"
},
{
"address":649,
"contract":"Unknown",
"debug":"<DEBUG-DATA>",
"description":"This binary subtraction operation can result in integer underflow.\n",
"function":"sendeth(address,uint256)",
"max_gas_used":1774,
"min_gas_used":1299,
"swc-id":"101",
"title":"Integer Underflow",
"type":"Warning"
} }
], ],
"success": true "success":true
} }

@ -1,16 +1,28 @@
# Analysis results for test-filename.sol # Analysis results for test-filename.sol
## Integer Overflow
- SWC ID: 101
- Type: Warning
- Contract: Unknown
- Function name: `sendeth(address,uint256)`
- PC address: 567
- Estimated Gas Usage: 768 - 1053
### Description
This binary subtraction operation can result in integer overflow.
## Integer Underflow ## Integer Underflow
- SWC ID: 101 - SWC ID: 101
- Type: Warning - Type: Warning
- Contract: Unknown - Contract: Unknown
- Function name: `sendeth(address,uint256)` - Function name: `sendeth(address,uint256)`
- PC address: 567 - PC address: 567
- Estimated Gas Usage: 750 - 1035 - Estimated Gas Usage: 1299 - 1774
### Description ### Description
The subtraction can result in an integer underflow. This binary subtraction operation can result in integer underflow.
## Integer Underflow ## Integer Underflow
- SWC ID: 101 - SWC ID: 101
@ -18,8 +30,8 @@ The subtraction can result in an integer underflow.
- Contract: Unknown - Contract: Unknown
- Function name: `sendeth(address,uint256)` - Function name: `sendeth(address,uint256)`
- PC address: 649 - PC address: 649
- Estimated Gas Usage: 1283 - 1758 - Estimated Gas Usage: 1299 - 1774
### Description ### Description
The subtraction can result in an integer underflow. This binary subtraction operation can result in integer underflow.

@ -1,11 +1,22 @@
==== Integer Overflow ====
SWC ID: 101
Type: Warning
Contract: Unknown
Function name: sendeth(address,uint256)
PC address: 567
Estimated Gas Usage: 768 - 1053
This binary subtraction operation can result in integer overflow.
--------------------
==== Integer Underflow ==== ==== Integer Underflow ====
SWC ID: 101 SWC ID: 101
Type: Warning Type: Warning
Contract: Unknown Contract: Unknown
Function name: sendeth(address,uint256) Function name: sendeth(address,uint256)
PC address: 567 PC address: 567
Estimated Gas Usage: 750 - 1035 Estimated Gas Usage: 1299 - 1774
The subtraction can result in an integer underflow. This binary subtraction operation can result in integer underflow.
-------------------- --------------------
@ -15,8 +26,8 @@ Type: Warning
Contract: Unknown Contract: Unknown
Function name: sendeth(address,uint256) Function name: sendeth(address,uint256)
PC address: 649 PC address: 649
Estimated Gas Usage: 1283 - 1758 Estimated Gas Usage: 1299 - 1774
The subtraction can result in an integer underflow. This binary subtraction operation can result in integer underflow.
-------------------- --------------------

@ -1 +1,42 @@
{"error": null, "issues": [{"address": 196, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", "function": "callchecked()", "max_gas_used": 1210, "min_gas_used": 599, "swc-id": "107", "title": "External call", "type": "Informational"}, {"address": 285, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", "function": "callnotchecked()", "max_gas_used": 1232, "min_gas_used": 621, "swc-id": "107", "title": "External call", "type": "Informational"}, {"address": 290, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "callnotchecked()", "max_gas_used": 35941, "min_gas_used": 1330, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true} {
"error": null,
"issues": [
{
"address": 196,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.",
"function": "callchecked()",
"max_gas_used": 1210,
"min_gas_used": 599,
"swc-id": "107",
"title": "External call",
"type": "Informational"
},
{
"address": 285,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.",
"function": "callnotchecked()",
"max_gas_used": 1232,
"min_gas_used": 621,
"swc-id": "107",
"title": "External call",
"type": "Informational"
},
{
"address": 285,
"contract": "Unknown",
"debug": "<DEBUG-DATA>",
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
"function": "callnotchecked()",
"max_gas_used": 35950,
"min_gas_used": 1339,
"swc-id": "104",
"title": "Unchecked CALL return value",
"type": "Informational"
}
],
"success": true
}

@ -29,8 +29,8 @@ The contract executes a function call to an external address. Verify that the co
- Type: Informational - Type: Informational
- Contract: Unknown - Contract: Unknown
- Function name: `callnotchecked()` - Function name: `callnotchecked()`
- PC address: 290 - PC address: 285
- Estimated Gas Usage: 1330 - 35941 - Estimated Gas Usage: 1339 - 35950
### Description ### Description

@ -23,8 +23,8 @@ SWC ID: 104
Type: Informational Type: Informational
Contract: Unknown Contract: Unknown
Function name: callnotchecked() Function name: callnotchecked()
PC address: 290 PC address: 285
Estimated Gas Usage: 1330 - 35941 Estimated Gas Usage: 1339 - 35950
The return value of an external call is not checked. Note that execution continue even if the called contract throws. The return value of an external call is not checked. Note that execution continue even if the called contract throws.
-------------------- --------------------

@ -1,30 +1,42 @@
{ {
"error": null, "error":null,
"issues": [ "issues":[
{ {
"address": 567, "address":567,
"contract": "Unknown", "contract":"Unknown",
"debug": "<DEBUG-DATA>", "debug":"<DEBUG-DATA>",
"description": "The subtraction can result in an integer underflow.\n", "description":"This binary subtraction operation can result in integer overflow.\n",
"function": "sendeth(address,uint256)", "function":"sendeth(address,uint256)",
"max_gas_used": 1035, "max_gas_used":1053,
"min_gas_used": 750, "min_gas_used":768,
"swc-id": "101", "swc-id":"101",
"title": "Integer Underflow", "title":"Integer Overflow",
"type": "Warning" "type":"Warning"
}, },
{ {
"address": 649, "address":567,
"contract": "Unknown", "contract":"Unknown",
"debug": "<DEBUG-DATA>", "debug":"<DEBUG-DATA>",
"description": "The subtraction can result in an integer underflow.\n", "description":"This binary subtraction operation can result in integer underflow.\n",
"function": "sendeth(address,uint256)", "function":"sendeth(address,uint256)",
"max_gas_used": 1758, "max_gas_used":1774,
"min_gas_used": 1283, "min_gas_used":1299,
"swc-id": "101", "swc-id":"101",
"title": "Integer Underflow", "title":"Integer Underflow",
"type": "Warning" "type":"Warning"
},
{
"address":649,
"contract":"Unknown",
"debug":"<DEBUG-DATA>",
"description":"This binary subtraction operation can result in integer underflow.\n",
"function":"sendeth(address,uint256)",
"max_gas_used":1774,
"min_gas_used":1299,
"swc-id":"101",
"title":"Integer Underflow",
"type":"Warning"
} }
], ],
"success": true "success":true
} }

@ -1,16 +1,28 @@
# Analysis results for test-filename.sol # Analysis results for test-filename.sol
## Integer Overflow
- SWC ID: 101
- Type: Warning
- Contract: Unknown
- Function name: `sendeth(address,uint256)`
- PC address: 567
- Estimated Gas Usage: 768 - 1053
### Description
This binary subtraction operation can result in integer overflow.
## Integer Underflow ## Integer Underflow
- SWC ID: 101 - SWC ID: 101
- Type: Warning - Type: Warning
- Contract: Unknown - Contract: Unknown
- Function name: `sendeth(address,uint256)` - Function name: `sendeth(address,uint256)`
- PC address: 567 - PC address: 567
- Estimated Gas Usage: 750 - 1035 - Estimated Gas Usage: 1299 - 1774
### Description ### Description
The subtraction can result in an integer underflow. This binary subtraction operation can result in integer underflow.
## Integer Underflow ## Integer Underflow
- SWC ID: 101 - SWC ID: 101
@ -18,8 +30,8 @@ The subtraction can result in an integer underflow.
- Contract: Unknown - Contract: Unknown
- Function name: `sendeth(address,uint256)` - Function name: `sendeth(address,uint256)`
- PC address: 649 - PC address: 649
- Estimated Gas Usage: 1283 - 1758 - Estimated Gas Usage: 1299 - 1774
### Description ### Description
The subtraction can result in an integer underflow. This binary subtraction operation can result in integer underflow.

@ -1,11 +1,22 @@
==== Integer Overflow ====
SWC ID: 101
Type: Warning
Contract: Unknown
Function name: sendeth(address,uint256)
PC address: 567
Estimated Gas Usage: 768 - 1053
This binary subtraction operation can result in integer overflow.
--------------------
==== Integer Underflow ==== ==== Integer Underflow ====
SWC ID: 101 SWC ID: 101
Type: Warning Type: Warning
Contract: Unknown Contract: Unknown
Function name: sendeth(address,uint256) Function name: sendeth(address,uint256)
PC address: 567 PC address: 567
Estimated Gas Usage: 750 - 1035 Estimated Gas Usage: 1299 - 1774
The subtraction can result in an integer underflow. This binary subtraction operation can result in integer underflow.
-------------------- --------------------
@ -15,8 +26,8 @@ Type: Warning
Contract: Unknown Contract: Unknown
Function name: sendeth(address,uint256) Function name: sendeth(address,uint256)
PC address: 649 PC address: 649
Estimated Gas Usage: 1283 - 1758 Estimated Gas Usage: 1299 - 1774
The subtraction can result in an integer underflow. This binary subtraction operation can result in integer underflow.
-------------------- --------------------

Loading…
Cancel
Save