github.com/cuiweixie/go-ethereum@v1.8.2-0.20180303084001-66cd41af1e38/core/vm/analysis.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package vm
    18  
    19  import (
    20  	"math/big"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  )
    24  
    25  // destinations stores one map per contract (keyed by hash of code).
    26  // The maps contain an entry for each location of a JUMPDEST
    27  // instruction.
    28  type destinations map[common.Hash]bitvec
    29  
    30  // has checks whether code has a JUMPDEST at dest.
    31  func (d destinations) has(codehash common.Hash, code []byte, dest *big.Int) bool {
    32  	// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
    33  	// Don't bother checking for JUMPDEST in that case.
    34  	udest := dest.Uint64()
    35  	if dest.BitLen() >= 63 || udest >= uint64(len(code)) {
    36  		return false
    37  	}
    38  
    39  	m, analysed := d[codehash]
    40  	if !analysed {
    41  		m = codeBitmap(code)
    42  		d[codehash] = m
    43  	}
    44  	return OpCode(code[udest]) == JUMPDEST && m.codeSegment(udest)
    45  }
    46  
    47  // bitvec is a bit vector which maps bytes in a program.
    48  // An unset bit means the byte is an opcode, a set bit means
    49  // it's data (i.e. argument of PUSHxx).
    50  type bitvec []byte
    51  
    52  func (bits *bitvec) set(pos uint64) {
    53  	(*bits)[pos/8] |= 0x80 >> (pos % 8)
    54  }
    55  func (bits *bitvec) set8(pos uint64) {
    56  	(*bits)[pos/8] |= 0xFF >> (pos % 8)
    57  	(*bits)[pos/8+1] |= ^(0xFF >> (pos % 8))
    58  }
    59  
    60  // codeSegment checks if the position is in a code segment.
    61  func (bits *bitvec) codeSegment(pos uint64) bool {
    62  	return ((*bits)[pos/8] & (0x80 >> (pos % 8))) == 0
    63  }
    64  
    65  // codeBitmap collects data locations in code.
    66  func codeBitmap(code []byte) bitvec {
    67  	// The bitmap is 4 bytes longer than necessary, in case the code
    68  	// ends with a PUSH32, the algorithm will push zeroes onto the
    69  	// bitvector outside the bounds of the actual code.
    70  	bits := make(bitvec, len(code)/8+1+4)
    71  	for pc := uint64(0); pc < uint64(len(code)); {
    72  		op := OpCode(code[pc])
    73  
    74  		if op >= PUSH1 && op <= PUSH32 {
    75  			numbits := op - PUSH1 + 1
    76  			pc++
    77  			for ; numbits >= 8; numbits -= 8 {
    78  				bits.set8(pc) // 8
    79  				pc += 8
    80  			}
    81  			for ; numbits > 0; numbits-- {
    82  				bits.set(pc)
    83  				pc++
    84  			}
    85  		} else {
    86  			pc++
    87  		}
    88  	}
    89  	return bits
    90  }