github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/core/vm/analysis.go (about) 1 package vm 2 3 import ( 4 "math/big" 5 6 "github.com/quickchainproject/quickchain/common" 7 ) 8 9 // destinations stores one map per contract (keyed by hash of code). 10 // The maps contain an entry for each location of a JUMPDEST 11 // instruction. 12 type destinations map[common.Hash]bitvec 13 14 // has checks whether code has a JUMPDEST at dest. 15 func (d destinations) has(codehash common.Hash, code []byte, dest *big.Int) bool { 16 // PC cannot go beyond len(code) and certainly can't be bigger than 63bits. 17 // Don't bother checking for JUMPDEST in that case. 18 udest := dest.Uint64() 19 if dest.BitLen() >= 63 || udest >= uint64(len(code)) { 20 return false 21 } 22 23 m, analysed := d[codehash] 24 if !analysed { 25 m = codeBitmap(code) 26 d[codehash] = m 27 } 28 return OpCode(code[udest]) == JUMPDEST && m.codeSegment(udest) 29 } 30 31 // bitvec is a bit vector which maps bytes in a program. 32 // An unset bit means the byte is an opcode, a set bit means 33 // it's data (i.e. argument of PUSHxx). 34 type bitvec []byte 35 36 func (bits *bitvec) set(pos uint64) { 37 (*bits)[pos/8] |= 0x80 >> (pos % 8) 38 } 39 func (bits *bitvec) set8(pos uint64) { 40 (*bits)[pos/8] |= 0xFF >> (pos % 8) 41 (*bits)[pos/8+1] |= ^(0xFF >> (pos % 8)) 42 } 43 44 // codeSegment checks if the position is in a code segment. 45 func (bits *bitvec) codeSegment(pos uint64) bool { 46 return ((*bits)[pos/8] & (0x80 >> (pos % 8))) == 0 47 } 48 49 // codeBitmap collects data locations in code. 50 func codeBitmap(code []byte) bitvec { 51 // The bitmap is 4 bytes longer than necessary, in case the code 52 // ends with a PUSH32, the algorithm will push zeroes onto the 53 // bitvector outside the bounds of the actual code. 54 bits := make(bitvec, len(code)/8+1+4) 55 for pc := uint64(0); pc < uint64(len(code)); { 56 op := OpCode(code[pc]) 57 58 if op >= PUSH1 && op <= PUSH32 { 59 numbits := op - PUSH1 + 1 60 pc++ 61 for ; numbits >= 8; numbits -= 8 { 62 bits.set8(pc) // 8 63 pc += 8 64 } 65 for ; numbits > 0; numbits-- { 66 bits.set(pc) 67 pc++ 68 } 69 } else { 70 pc++ 71 } 72 } 73 return bits 74 }