danger.go raw

   1  package danger
   2  
   3  import (
   4  	"fmt"
   5  	"reflect"
   6  	"unsafe"
   7  )
   8  
   9  const maxInt = uintptr(int(^uint(0) >> 1))
  10  
  11  func SubsliceOffset(data []byte, subslice []byte) int {
  12  	datap := (*reflect.SliceHeader)(unsafe.Pointer(&data))
  13  	hlp := (*reflect.SliceHeader)(unsafe.Pointer(&subslice))
  14  
  15  	if hlp.Data < datap.Data {
  16  		panic(fmt.Errorf("subslice address (%d) is before data address (%d)", hlp.Data, datap.Data))
  17  	}
  18  	offset := hlp.Data - datap.Data
  19  
  20  	if offset > maxInt {
  21  		panic(fmt.Errorf("slice offset larger than int (%d)", offset))
  22  	}
  23  
  24  	intoffset := int(offset)
  25  
  26  	if intoffset > datap.Len {
  27  		panic(fmt.Errorf("slice offset (%d) is farther than data length (%d)", intoffset, datap.Len))
  28  	}
  29  
  30  	if intoffset+hlp.Len > datap.Len {
  31  		panic(fmt.Errorf("slice ends (%d+%d) is farther than data length (%d)", intoffset, hlp.Len, datap.Len))
  32  	}
  33  
  34  	return intoffset
  35  }
  36  
  37  func BytesRange(start []byte, end []byte) []byte {
  38  	if start == nil || end == nil {
  39  		panic("cannot call BytesRange with nil")
  40  	}
  41  	startp := (*reflect.SliceHeader)(unsafe.Pointer(&start))
  42  	endp := (*reflect.SliceHeader)(unsafe.Pointer(&end))
  43  
  44  	if startp.Data > endp.Data {
  45  		panic(fmt.Errorf("start pointer address (%d) is after end pointer address (%d)", startp.Data, endp.Data))
  46  	}
  47  
  48  	l := startp.Len
  49  	endLen := int(endp.Data-startp.Data) + endp.Len
  50  	if endLen > l {
  51  		l = endLen
  52  	}
  53  
  54  	if l > startp.Cap {
  55  		panic(fmt.Errorf("range length is larger than capacity"))
  56  	}
  57  
  58  	return start[:l]
  59  }
  60  
  61  func Stride(ptr unsafe.Pointer, size uintptr, offset int) unsafe.Pointer {
  62  	// TODO: replace with unsafe.Add when Go 1.17 is released
  63  	//   https://github.com/golang/go/issues/40481
  64  	return unsafe.Pointer(uintptr(ptr) + uintptr(int(size)*offset))
  65  }
  66