From fbf4a4323bbce68566641f42731eb1177391e52d Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Sun, 11 Oct 2015 17:59:38 -0700 Subject: [PATCH] fix memory leaks in VM --- vm/vm.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/vm/vm.go b/vm/vm.go index 7d60752e..49dfca5f 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -109,6 +109,8 @@ func (vm *VM) fireCallEvent(exception *string, output *[]byte, caller, callee *A } // CONTRACT appState is aware of caller and callee, so we can just mutate them. +// CONTRACT code and input are not mutated. +// CONTRACT returned 'ret' is a new compact slice. // value: To be transferred from caller to callee. Refunded upon error. // gas: Available gas. No refunds for gas. // code: May be nil, since the CALL opcode may be used to send value from contracts to accounts @@ -691,6 +693,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } + data = copyslice(data) if vm.evc != nil { eventID := types.EventStringLogEvent(callee.Address.Postfix(20)) fmt.Printf("eventID: %s\n", eventID) @@ -724,11 +727,12 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas newAccount := vm.appState.CreateAccount(callee) // Run the input to get the contract code. + // NOTE: no need to copy 'input' as per Call contract. ret, err_ := vm.Call(callee, newAccount, input, input, contractValue, gas) if err_ != nil { stack.Push(Zero256) } else { - newAccount.Code = ret // Set the code + newAccount.Code = ret // Set the code (ret need not be copied as per Call contract) stack.Push(newAccount.Address) } @@ -747,6 +751,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas if !ok { return nil, firstErr(err, ErrMemoryOutOfBounds) } + args = copyslice(args) // Ensure that gasLimit is reasonable if *gas < gasLimit { @@ -827,7 +832,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas return nil, firstErr(err, ErrMemoryOutOfBounds) } dbg.Printf(" => [%v, %v] (%d) 0x%X\n", offset, size, len(ret), ret) - return ret, nil + output = copyslice(ret) + return output, nil case SUICIDE: // 0xFF addr := stack.Pop() @@ -870,10 +876,15 @@ func subslice(data []byte, offset, length int64) (ret []byte, ok bool) { } else { ret, ok = data[offset:offset+length], true } - return } +func copyslice(src []byte) (dest []byte) { + dest = make([]byte, len(src)) + copy(dest, src) + return dest +} + func rightMostBytes(data []byte, n int) []byte { size := MinInt(len(data), n) offset := len(data) - size