github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/core/vm/analysis.go (about)

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