import pytest
from eth . _utils . numeric import ceil32
from mythril . laser . smt import simplify , symbol_factory , Concat , Extract
from mythril . laser . ethereum . state . machine_state import MachineState
from mythril . laser . ethereum . evm_exceptions import StackUnderflowException
from mythril . laser . ethereum . state . memory import Memory
memory_extension_test_data = [ ( 0 , 0 , 10 ) , ( 0 , 30 , 10 ) , ( 100 , 22 , 8 ) ]
@pytest . mark . parametrize (
" initial_size,start,extension_size " , memory_extension_test_data
)
def test_memory_extension ( initial_size , start , extension_size ) :
# Arrange
machine_state = MachineState ( gas_limit = 8000000 )
machine_state . memory = Memory ( )
machine_state . memory . extend ( initial_size )
# Act
machine_state . mem_extend ( start , extension_size )
# Assert
assert machine_state . memory_size == len ( machine_state . memory )
assert machine_state . memory_size == max (
initial_size , ( ceil32 ( start + extension_size ) / / 32 ) * 32
)
stack_pop_too_many_test_data = [ ( 0 , 1 ) , ( 0 , 2 ) , ( 5 , 1 ) , ( 5 , 10 ) ]
@pytest . mark . parametrize ( " initial_size,overflow " , stack_pop_too_many_test_data )
def test_stack_pop_too_many ( initial_size , overflow ) :
# Arrange
machine_state = MachineState ( 8000000 )
machine_state . stack = [ 42 ] * initial_size
# Act + Assert
with pytest . raises ( StackUnderflowException ) :
machine_state . pop ( initial_size + overflow )
stack_pop_test_data = [
( [ 1 , 2 , 3 ] , 2 , [ 3 , 2 ] ) ,
( [ 1 , 3 , 4 , 7 , 7 , 1 , 2 ] , 5 , [ 2 , 1 , 7 , 7 , 4 ] ) ,
]
@pytest . mark . parametrize ( " initial_stack,amount,expected " , stack_pop_test_data )
def test_stack_multiple_pop ( initial_stack , amount , expected ) :
# Arrange
machine_state = MachineState ( 8000000 )
machine_state . stack = initial_stack [ : ]
# Act
results = machine_state . pop ( amount )
# Assert
assert results == initial_stack [ - amount : ] [ : : - 1 ]
assert results == expected
assert len ( machine_state . stack ) == len ( initial_stack ) - amount
def test_stack_multiple_pop_ ( ) :
# Arrange
machine_state = MachineState ( 8000000 )
machine_state . stack = [ 1 , 2 , 3 ]
# Act
a , b = machine_state . pop ( 2 )
# Assert
assert a == 3
assert b == 2
def test_stack_single_pop ( ) :
# Arrange
machine_state = MachineState ( 8000000 )
machine_state . stack = [ 1 , 2 , 3 ]
# Act
result = machine_state . pop ( )
# Assert
assert isinstance ( result , int )
def test_memory_zeroed ( ) :
# Arrange
mem = Memory ( )
mem . extend ( 2000 + 32 )
# Act
mem [ 11 ] = 10
mem . write_word_at ( 2000 , 0x12345 )
# Assert
assert mem [ 10 ] == 0
assert mem [ 100 ] == 0
assert mem . get_word_at ( 1000 ) == 0
def test_memory_write ( ) :
# Arrange
mem = Memory ( )
mem . extend ( 200 + 32 )
a = symbol_factory . BitVecSym ( " a " , 256 )
b = symbol_factory . BitVecSym ( " b " , 8 )
# Act
mem [ 11 ] = 10
mem [ 12 ] = b
mem . write_word_at ( 200 , 0x12345 )
mem . write_word_at ( 100 , a )
# Assert
assert mem [ 0 ] == 0
assert mem [ 11 ] == 10
assert mem [ 200 + 31 ] == 0x45
assert mem . get_word_at ( 200 ) == 0x12345
assert simplify ( a == mem . get_word_at ( 100 ) )
assert simplify ( b == mem [ 12 ] )
def test_memory_symbolic ( ) :
# Arrange
mem = Memory ( )
mem . extend ( 200 + 32 )
a = symbol_factory . BitVecSym ( " a " , 256 )
b = symbol_factory . BitVecSym ( " b " , 256 )
# Act
mem . write_word_at ( a + symbol_factory . BitVecVal ( 1 , 256 ) , b )
# Assert
assert mem . get_word_at ( a ) == Concat (
symbol_factory . BitVecVal ( 0 , 256 ) , Extract ( 255 , 8 , b )
)
assert mem [ a ] == 0