From e17df3ebce03e1478194e1f2c3b82d157f4aaa2a Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Tue, 5 Mar 2019 09:18:40 +0100 Subject: [PATCH] core/vm: use 64-bit memory calculations --- core/vm/common.go | 42 +++++++++++++-- core/vm/interpreter.go | 2 +- core/vm/jump_table.go | 5 +- core/vm/memory_table.go | 116 +++++++++++++++++++++++----------------- 4 files changed, 107 insertions(+), 58 deletions(-) diff --git a/core/vm/common.go b/core/vm/common.go index 17de38decb..63bb3a746c 100644 --- a/core/vm/common.go +++ b/core/vm/common.go @@ -23,13 +23,47 @@ import ( "github.com/ethereum/go-ethereum/common/math" ) -// calculates the memory size required for a step -func calcMemSize(off, l *big.Int) *big.Int { +// calcMemSize64 calculates the required memory size, and returns +// the size and whether the result overflowed uint64 +func calcMemSize64(off, l *big.Int) (uint64, bool) { + // if length is zero, memsize is always zero, regardless of offset if l.Sign() == 0 { - return common.Big0 + return 0, true + } + // Check that neither offset nor length overflows + if off.BitLen() > 64 || l.BitLen() > 64 { + return 0, true } - return new(big.Int).Add(off, l) + offset64 := off.Uint64() + length64 := l.Uint64() + val := offset64 + length64 + // Check that the total doesn't overflow + if val < offset64 { + return 0, true + } + return val, false +} + +// calcMemSize64WithUint calculates the required memory size, and returns +// the size and whether the result overflowed uint64 +// Identical to calcMemSize64, but length is a uint64 +func calcMemSize64WithUint(off *big.Int, length64 uint64) (uint64, bool) { + // if length is zero, memsize is always zero, regardless of offset + if length64 == 0 { + return 0, true + } + // Check that offset doesn't overflow + if off.BitLen() > 64 { + return 0, true + } + offset64 := off.Uint64() + val := offset64 + length64 + // Check that the total doesn't overflow + if val < offset64 { + return 0, true + } + return val, false } // getData returns a slice from the data based on the start and size and pads diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 019210174f..572578b2b5 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -229,7 +229,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // calculate the new memory size and expand the memory to fit // the operation if operation.memorySize != nil { - memSize, overflow := bigUint64(operation.memorySize(stack)) + memSize, overflow := operation.memorySize(stack) if overflow { return nil, errGasUintOverflow } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 90d8e64dba..425436f9e5 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -18,7 +18,6 @@ package vm import ( "errors" - "math/big" "github.com/ethereum/go-ethereum/params" ) @@ -26,8 +25,8 @@ import ( type ( executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 - //stackValidationFunc func(*Stack) error - memorySizeFunc func(*Stack) *big.Int + // memorySizeFunc returns the required size, and whether the operation overflowed a uint64 + memorySizeFunc func(*Stack) (size uint64, overflow bool) ) var errGasUintOverflow = errors.New("gas uint64 overflow") diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index 8fa6c90ca7..4fcb41442c 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -16,82 +16,98 @@ package vm -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common/math" -) - -func memorySha3(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(1)) +func memorySha3(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(1)) } -func memoryCallDataCopy(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(2)) +func memoryCallDataCopy(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(2)) } -func memoryReturnDataCopy(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(2)) +func memoryReturnDataCopy(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(2)) } -func memoryCodeCopy(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(2)) +func memoryCodeCopy(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(2)) } -func memoryExtCodeCopy(stack *Stack) *big.Int { - return calcMemSize(stack.Back(1), stack.Back(3)) +func memoryExtCodeCopy(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(1), stack.Back(3)) } -func memoryMLoad(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), big.NewInt(32)) +func memoryMLoad(stack *Stack) (uint64, bool) { + return calcMemSize64WithUint(stack.Back(0), 32) } -func memoryMStore8(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), big.NewInt(1)) +func memoryMStore8(stack *Stack) (uint64, bool) { + return calcMemSize64WithUint(stack.Back(0), 1) } -func memoryMStore(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), big.NewInt(32)) +func memoryMStore(stack *Stack) (uint64, bool) { + return calcMemSize64WithUint(stack.Back(0), 32) } -func memoryCreate(stack *Stack) *big.Int { - return calcMemSize(stack.Back(1), stack.Back(2)) +func memoryCreate(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(1), stack.Back(2)) } -func memoryCreate2(stack *Stack) *big.Int { - return calcMemSize(stack.Back(1), stack.Back(2)) +func memoryCreate2(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(1), stack.Back(2)) } -func memoryCall(stack *Stack) *big.Int { - x := calcMemSize(stack.Back(5), stack.Back(6)) - y := calcMemSize(stack.Back(3), stack.Back(4)) - - return math.BigMax(x, y) +func memoryCall(stack *Stack) (uint64, bool) { + x, overflow := calcMemSize64(stack.Back(5), stack.Back(6)) + if overflow { + return 0, true + } + y, overflow := calcMemSize64(stack.Back(3), stack.Back(4)) + if overflow { + return 0, true + } + if x > y { + return x, false + } + return y, false +} +func memoryDelegateCall(stack *Stack) (uint64, bool) { + x, overflow := calcMemSize64(stack.Back(4), stack.Back(5)) + if overflow { + return 0, true + } + y, overflow := calcMemSize64(stack.Back(2), stack.Back(3)) + if overflow { + return 0, true + } + if x > y { + return x, false + } + return y, false } -func memoryDelegateCall(stack *Stack) *big.Int { - x := calcMemSize(stack.Back(4), stack.Back(5)) - y := calcMemSize(stack.Back(2), stack.Back(3)) - - return math.BigMax(x, y) +func memoryStaticCall(stack *Stack) (uint64, bool) { + x, overflow := calcMemSize64(stack.Back(4), stack.Back(5)) + if overflow { + return 0, true + } + y, overflow := calcMemSize64(stack.Back(2), stack.Back(3)) + if overflow { + return 0, true + } + if x > y { + return x, false + } + return y, false } -func memoryStaticCall(stack *Stack) *big.Int { - x := calcMemSize(stack.Back(4), stack.Back(5)) - y := calcMemSize(stack.Back(2), stack.Back(3)) - - return math.BigMax(x, y) +func memoryReturn(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(1)) } -func memoryReturn(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(1)) +func memoryRevert(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(1)) } -func memoryRevert(stack *Stack) *big.Int { - return calcMemSize(stack.Back(0), stack.Back(1)) -} - -func memoryLog(stack *Stack) *big.Int { - mSize, mStart := stack.Back(1), stack.Back(0) - return calcMemSize(mStart, mSize) +func memoryLog(stack *Stack) (uint64, bool) { + return calcMemSize64(stack.Back(0), stack.Back(1)) }