diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 6103314c21..353632f13a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -30,7 +30,8 @@ import ( var ( bigZero = new(big.Int) - errWriteProtection = errors.New("evm write protection") + errWriteProtection = errors.New("evm: write protection") + errReadOutOfBound = errors.New("evm: read out of bound") ) func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { @@ -778,9 +779,14 @@ func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, cOff = stack.pop() l = stack.pop() ) - memory.Set(mOff.Uint64(), l.Uint64(), getData(evm.interpreter.returnData, cOff, l)) + defer evm.interpreter.intPool.put(mOff, cOff, l) + + cEnd := new(big.Int).Add(cOff, l) + if cEnd.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < cEnd.Uint64() { + return nil, errReadOutOfBound + } + memory.Set(mOff.Uint64(), l.Uint64(), evm.interpreter.returnData[cOff.Uint64():cEnd.Uint64()]) - evm.interpreter.intPool.put(mOff, cOff, l) return nil, nil } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index eaca43c767..a64d1bab5a 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -93,7 +93,10 @@ func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack if in.evm.chainRules.IsMetropolis { if in.readonly { // if the interpreter is operating in readonly mode, make sure no - // state-modifying operation is performed. + // state-modifying operation is performed. The 4th stack item + // for a call operation is the value. Transfering value from one + // account to the others means the state is modified and should also + // return with an error. if operation.writes || ((op == CALL || op == CALLCODE) && stack.Back(3).BitLen() > 0) { return errWriteProtection diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index cdb64afaf5..14f604fe88 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -84,7 +84,7 @@ func NewMetropolisInstructionSet() [256]operation { } instructionSet[RETURNDATASIZE] = operation{ execute: opReturnDataSize, - gasCost: constGasFunc(0), // TODO + gasCost: constGasFunc(GasQuickStep), validateStack: makeStackFunc(0, 1), valid: true, }