Add tests for push, swap and dup

pull/494/head
Nikhil Parasaram 6 years ago
parent 726924276b
commit 404b8d9aee
  1. 6
      mythril/laser/ethereum/exceptions.py
  2. 45
      mythril/laser/ethereum/instructions.py
  3. 12
      mythril/laser/ethereum/state.py
  4. 38
      tests/laser/evm_testsuite/evm_test.py

@ -0,0 +1,6 @@
class VmException(Exception):
pass
class StopSignal(Exception):
pass

@ -2,7 +2,6 @@ import binascii
import logging
from copy import copy, deepcopy
import ethereum.opcodes as opcodes
from ethereum import utils
from z3 import BitVec, Extract, UDiv, simplify, Concat, ULT, UGT, BitVecNumRef, Not, \
is_false, is_expr, ExprRef, URem, SRem
@ -11,22 +10,16 @@ from z3 import BitVecVal, If, BoolRef
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.state import GlobalState, MachineState, Environment, CalldataType
from mythril.laser.ethereum.state import GlobalState, CalldataType
import mythril.laser.ethereum.natives as natives
from mythril.laser.ethereum.transaction import MessageCallTransaction, TransactionEndSignal, TransactionStartSignal, ContractCreationTransaction
from mythril.laser.ethereum.transaction import MessageCallTransaction, TransactionStartSignal, \
ContractCreationTransaction
from mythril.laser.ethereum.exceptions import VmException
TT256 = 2 ** 256
TT256M1 = 2 ** 256 - 1
class StackUnderflowException(Exception):
pass
class StopSignal(Exception):
pass
def instruction(func):
""" Wrapper that handles copy and original return """
@ -75,14 +68,20 @@ class Instruction:
@instruction
def push_(self, global_state):
value = BitVecVal(int(global_state.get_current_instruction()['argument'][2:], 16), 256)
try:
value = BitVecVal(int(global_state.get_current_instruction()['argument'][2:], 16), 256)
except ValueError:
raise VmException('Invalid Argument for PUSH')
global_state.mstate.stack.append(value)
return [global_state]
@instruction
def dup_(self, global_state):
value = int(global_state.get_current_instruction()['opcode'][3:], 10)
global_state.mstate.stack.append(global_state.mstate.stack[-value])
try:
global_state.mstate.stack.append(global_state.mstate.stack[-value])
except IndexError:
raise VmException('Trying to duplicate out of bounds stack elements')
return [global_state]
@instruction
@ -92,7 +91,7 @@ class Instruction:
stack = global_state.mstate.stack
stack[-depth - 1], stack[-1] = stack[-1], stack[-depth - 1]
except IndexError:
raise StackUnderflowException()
raise VmException('Stack underflow exception')
return [global_state]
@instruction
@ -100,7 +99,7 @@ class Instruction:
try:
global_state.mstate.stack.pop()
except IndexError:
raise StackUnderflowException()
raise VmException('Stack underflow exception')
return [global_state]
@instruction
@ -115,7 +114,7 @@ class Instruction:
stack.append(op1 & op2)
except IndexError:
raise StackUnderflowException()
raise VmException('Stack underflow exception')
return [global_state]
@instruction
@ -132,7 +131,7 @@ class Instruction:
stack.append(op1 | op2)
except IndexError: # Stack underflow
raise StackUnderflowException()
raise VmException('Stack underflow exception')
return [global_state]
@instruction
@ -500,13 +499,12 @@ class Instruction:
return [global_state]
try:
data = b''
state.mem_extend(index, length)
data = b''.join([util.get_concrete_int(i).to_bytes(1, byteorder='big')
for i in state.memory[index: index + length]])
for i in range(index, index + length):
data += util.get_concrete_int(state.memory[i]).to_bytes(1, byteorder='big')
i += 1
# FIXME: broad exception catch
except:
except AttributeError:
svar = str(state.memory[index])
@ -680,7 +678,7 @@ class Instruction:
try:
op0, value = state.stack.pop(), state.stack.pop()
except IndexError:
raise StackUnderflowException()
raise VmException('Stack underflow exception')
try:
mstart = util.get_concrete_int(op0)
@ -916,6 +914,7 @@ class Instruction:
@instruction
def call_(self, global_state):
instr = global_state.get_current_instruction()
environment = global_state.environment

@ -2,6 +2,7 @@ from z3 import BitVec, BitVecVal
from copy import copy, deepcopy
from enum import Enum
from random import randint
from mythril.laser.ethereum.exceptions import VmException
class CalldataType(Enum):
@ -141,8 +142,15 @@ class MachineState:
:param start: Start of memory extension
:param size: Size of memory extension
"""
self.memory += [0] * max(0, start + size - self.memory_size)
if self.memory_size > start + size:
return
m_extend = (start + size - self.memory_size)
try:
self.memory.extend(bytearray(m_extend))
except MemoryError:
raise VmException('error extending memory')
return True
def memory_write(self, offset, data):
""" Writes data to memory starting at offset """
self.mem_extend(offset, len(data))

@ -1,3 +1,4 @@
from mythril.laser.ethereum.exceptions import VmException
from mythril.laser.ethereum.svm import LaserEVM
from mythril.laser.ethereum.state import Account
from mythril.disassembler.disassembly import Disassembly
@ -11,7 +12,7 @@ import pytest
evm_test_dir = Path(__file__).parent / 'VMTests'
test_types = ['vmArithmeticTest', 'vmBitwiseLogicOperation']
test_types = ['vmArithmeticTest', 'vmBitwiseLogicOperation', 'vmPushDupSwapTest']
def load_test_data(designations):
@ -27,7 +28,7 @@ def load_test_data(designations):
action = data['exec']
post_condition = data['post']
post_condition = data.get('post', {})
return_data.append((test_name, pre_condition, action, post_condition))
@ -51,20 +52,28 @@ def test_vmtest(test_name: str, pre_condition: dict, action: dict, post_conditio
# Act
laser_evm.time = datetime.now()
execute_message_call(
laser_evm,
callee_address=action['address'],
caller_address=action['caller'],
origin_address=action['origin'],
code=action['code'][2:],
gas=action['gas'],
data=binascii.a2b_hex(action['data'][2:]),
gas_price=int(action['gasPrice'], 16),
value=int(action['value'], 16)
)
try:
execute_message_call(
laser_evm,
callee_address=action['address'],
caller_address=action['caller'],
origin_address=action['origin'],
code=action['code'][2:],
gas=action['gas'],
data=binascii.a2b_hex(action['data'][2:]),
gas_price=int(action['gasPrice'], 16),
value=int(action['value'], 16)
)
except VmException:
return
# Assert
assert len(laser_evm.open_states) == 1
if 'Suicide' not in test_name:
assert len(laser_evm.open_states) == 1
else:
assert len(laser_evm.open_states) == 0
return
world_state = laser_evm.open_states[0]
for address, details in post_condition.items():
@ -76,4 +85,5 @@ def test_vmtest(test_name: str, pre_condition: dict, action: dict, post_conditio
for index, value in details['storage'].items():
expected = int(value, 16)
actual = get_concrete_int(account.storage[int(index, 16)])
print(actual, expected)
assert actual == expected

Loading…
Cancel
Save