core/vm: fix possible jump table race

This commit is contained in:
Jeffrey Wilcke 2016-03-19 01:24:23 +01:00
parent 34b622a248
commit e70a2b4491
3 changed files with 27 additions and 31 deletions

View file

@ -1,10 +1,6 @@
package vm package vm
import ( import "math/big"
"math/big"
"github.com/ethereum/go-ethereum/params"
)
type jumpPtr struct { type jumpPtr struct {
fn instrFn fn instrFn
@ -13,19 +9,22 @@ type jumpPtr struct {
type vmJumpTable [256]jumpPtr type vmJumpTable [256]jumpPtr
func (jt vmJumpTable) init(blockNumber *big.Int) { var (
homesteadJumpTable = newJumpTable(true)
frontierJumpTable = newJumpTable(false)
)
func newJumpTable(homestead bool) vmJumpTable {
var jumpTable vmJumpTable
// when initialising a new VM execution we must first check the homestead // when initialising a new VM execution we must first check the homestead
// changes. // changes.
if params.IsHomestead(blockNumber) { if homestead {
jumpTable[DELEGATECALL] = jumpPtr{opDelegateCall, true} jumpTable[DELEGATECALL] = jumpPtr{opDelegateCall, true}
} else { } else {
jumpTable[DELEGATECALL] = jumpPtr{nil, false} jumpTable[DELEGATECALL] = jumpPtr{nil, false}
} }
}
var jumpTable vmJumpTable
func init() {
jumpTable[ADD] = jumpPtr{opAdd, true} jumpTable[ADD] = jumpPtr{opAdd, true}
jumpTable[SUB] = jumpPtr{opSub, true} jumpTable[SUB] = jumpPtr{opSub, true}
jumpTable[MUL] = jumpPtr{opMul, true} jumpTable[MUL] = jumpPtr{opMul, true}
@ -156,4 +155,6 @@ func init() {
jumpTable[JUMP] = jumpPtr{nil, true} jumpTable[JUMP] = jumpPtr{nil, true}
jumpTable[JUMPI] = jumpPtr{nil, true} jumpTable[JUMPI] = jumpPtr{nil, true}
jumpTable[STOP] = jumpPtr{nil, true} jumpTable[STOP] = jumpPtr{nil, true}
return jumpTable
} }

View file

@ -1,24 +1,13 @@
package vm package vm
import ( import "testing"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/params"
)
func TestInit(t *testing.T) { func TestInit(t *testing.T) {
params.HomesteadBlock = big.NewInt(1) if frontierJumpTable[DELEGATECALL].valid {
jumpTable.init(big.NewInt(0))
if jumpTable[DELEGATECALL].valid {
t.Error("Expected DELEGATECALL not to be present") t.Error("Expected DELEGATECALL not to be present")
} }
for _, n := range []int64{1, 2, 100} { if !homesteadJumpTable[DELEGATECALL].valid {
jumpTable.init(big.NewInt(n)) t.Error("Expected DELEGATECALL not to be present")
if !jumpTable[DELEGATECALL].valid {
t.Error("Expected DELEGATECALL to be present for block", n)
}
} }
} }

View file

@ -31,14 +31,20 @@ import (
// Vm is an EVM and implements VirtualMachine // Vm is an EVM and implements VirtualMachine
type Vm struct { type Vm struct {
env Environment env Environment
jumpTable vmJumpTable
} }
// New returns a new Vm // New returns a new Vm
func New(env Environment) *Vm { func New(env Environment) *Vm {
// init the jump table. Also prepares the homestead changes evm := &Vm{env: env}
jumpTable.init(env.BlockNumber())
return &Vm{env: env} if params.IsHomestead(env.BlockNumber()) {
evm.jumpTable = homesteadJumpTable
} else {
evm.jumpTable = frontierJumpTable
}
return evm
} }
// Run loops and evaluates the contract's code with the given input data // Run loops and evaluates the contract's code with the given input data
@ -169,7 +175,7 @@ func (self *Vm) Run(contract *Contract, input []byte) (ret []byte, err error) {
mem.Resize(newMemSize.Uint64()) mem.Resize(newMemSize.Uint64())
// Add a log message // Add a log message
self.log(pc, op, contract.Gas, cost, mem, stack, contract, nil) self.log(pc, op, contract.Gas, cost, mem, stack, contract, nil)
if opPtr := jumpTable[op]; opPtr.valid { if opPtr := self.jumpTable[op]; opPtr.valid {
if opPtr.fn != nil { if opPtr.fn != nil {
opPtr.fn(instruction{}, &pc, self.env, contract, mem, stack) opPtr.fn(instruction{}, &pc, self.env, contract, mem, stack)
} else { } else {