mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-26 05:17:22 +00:00
c1197d7881
* Add static analysis for unsafe uint casting * Fix violations of uintcast * go mod tidy * Add exclusion to nogo for darwin build * Add test for math.Int * Move some things to const so they are assured not to exceed int64 * Self review * lint * fix tests * fix test * Add init check for non 64 bit OS * Move new deps from WORKSPACE to deps.bzl * fix bazel build for go analysis runs * Update BUILD.bazel Remove TODO * add math.AddInt method * Add new test casts * Add case where builtin functions and declared functions are covered * Fix new findings * cleanup Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com> Co-authored-by: Nishant Das <nishdas93@gmail.com>
226 lines
5.3 KiB
Go
226 lines
5.3 KiB
Go
// Originally from https://github.com/mdempsky/maligned, adapted to work with nogo.
|
|
|
|
// Copyright 2013 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package maligned
|
|
|
|
import (
|
|
"fmt"
|
|
"go/build"
|
|
"go/token"
|
|
"go/types"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
func malign(_ token.Pos, str *types.Struct) error {
|
|
wordSize := int64(8)
|
|
maxAlign := int64(8)
|
|
switch build.Default.GOARCH {
|
|
case "386", "arm":
|
|
wordSize, maxAlign = 4, 4
|
|
case "amd64p32":
|
|
wordSize = 4
|
|
}
|
|
|
|
s := gcSizes{wordSize, maxAlign}
|
|
sz, opt := s.Sizeof(str), optimalSize(str, &s)
|
|
if sz != opt {
|
|
return fmt.Errorf("maligned struct of size %d could be %d if fields were sorted by type. See: https://bit.ly/malignedstruct\n\nOptimal sort order is\n%s", sz, opt, optimalSort(s, str))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func optimalSort(sizes gcSizes, str *types.Struct) string {
|
|
nf := str.NumFields()
|
|
fields := make([]*types.Var, nf)
|
|
alignofs := make([]int64, nf)
|
|
sizeofs := make([]int64, nf)
|
|
for i := 0; i < nf; i++ {
|
|
fields[i] = str.Field(i)
|
|
ft := fields[i].Type()
|
|
alignofs[i] = sizes.Alignof(ft)
|
|
sizeofs[i] = sizes.Sizeof(ft)
|
|
}
|
|
sort.Sort(&byAlignAndSize{fields, alignofs, sizeofs})
|
|
// Reverse fields
|
|
for left, right := 0, len(fields)-1; left < right; left, right = left+1, right-1 {
|
|
fields[left], fields[right] = fields[right], fields[left]
|
|
}
|
|
ss := make([]string, nf)
|
|
for i, f := range fields {
|
|
ss[i] = fmt.Sprintf(" %s %s", f.Name(), f.Type().String())
|
|
}
|
|
|
|
return strings.Join(ss, "\n")
|
|
}
|
|
|
|
func optimalSize(str *types.Struct, sizes *gcSizes) int64 {
|
|
nf := str.NumFields()
|
|
fields := make([]*types.Var, nf)
|
|
alignofs := make([]int64, nf)
|
|
sizeofs := make([]int64, nf)
|
|
for i := 0; i < nf; i++ {
|
|
fields[i] = str.Field(i)
|
|
ft := fields[i].Type()
|
|
alignofs[i] = sizes.Alignof(ft)
|
|
sizeofs[i] = sizes.Sizeof(ft)
|
|
}
|
|
sort.Sort(&byAlignAndSize{fields, alignofs, sizeofs})
|
|
return sizes.Sizeof(types.NewStruct(fields, nil))
|
|
}
|
|
|
|
type byAlignAndSize struct {
|
|
fields []*types.Var
|
|
alignofs []int64
|
|
sizeofs []int64
|
|
}
|
|
|
|
// Len --
|
|
func (s *byAlignAndSize) Len() int { return len(s.fields) }
|
|
|
|
// Swap --
|
|
func (s *byAlignAndSize) Swap(i, j int) {
|
|
s.fields[i], s.fields[j] = s.fields[j], s.fields[i]
|
|
s.alignofs[i], s.alignofs[j] = s.alignofs[j], s.alignofs[i]
|
|
s.sizeofs[i], s.sizeofs[j] = s.sizeofs[j], s.sizeofs[i]
|
|
}
|
|
|
|
// Less --
|
|
func (s *byAlignAndSize) Less(i, j int) bool {
|
|
// Place zero sized objects before non-zero sized objects.
|
|
if s.sizeofs[i] == 0 && s.sizeofs[j] != 0 {
|
|
return true
|
|
}
|
|
if s.sizeofs[j] == 0 && s.sizeofs[i] != 0 {
|
|
return false
|
|
}
|
|
|
|
// Next, place more tightly aligned objects before less tightly aligned objects.
|
|
if s.alignofs[i] != s.alignofs[j] {
|
|
return s.alignofs[i] > s.alignofs[j]
|
|
}
|
|
|
|
// Lastly, order by size.
|
|
if s.sizeofs[i] != s.sizeofs[j] {
|
|
return s.sizeofs[i] > s.sizeofs[j]
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Code below based on go/types.StdSizes.
|
|
|
|
type gcSizes struct {
|
|
WordSize int64
|
|
MaxAlign int64
|
|
}
|
|
|
|
// Alignof --
|
|
func (s *gcSizes) Alignof(T types.Type) int64 {
|
|
// NOTE: On amd64, complex64 is 8 byte aligned,
|
|
// even though float32 is only 4 byte aligned.
|
|
|
|
// For arrays and structs, alignment is defined in terms
|
|
// of alignment of the elements and fields, respectively.
|
|
switch t := T.Underlying().(type) {
|
|
case *types.Array:
|
|
// spec: "For a variable x of array type: unsafe.Alignof(x)
|
|
// is the same as unsafe.Alignof(x[0]), but at least 1."
|
|
return s.Alignof(t.Elem())
|
|
case *types.Struct:
|
|
// spec: "For a variable x of struct type: unsafe.Alignof(x)
|
|
// is the largest of the values unsafe.Alignof(x.f) for each
|
|
// field f of x, but at least 1."
|
|
max := int64(1)
|
|
for i, nf := 0, t.NumFields(); i < nf; i++ {
|
|
if a := s.Alignof(t.Field(i).Type()); a > max {
|
|
max = a
|
|
}
|
|
}
|
|
return max
|
|
}
|
|
a := s.Sizeof(T) // may be 0
|
|
// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
|
|
if a < 1 {
|
|
return 1
|
|
}
|
|
if a > s.MaxAlign {
|
|
return s.MaxAlign
|
|
}
|
|
return a
|
|
}
|
|
|
|
var basicSizes = [...]byte{
|
|
types.Bool: 1,
|
|
types.Int8: 1,
|
|
types.Int16: 2,
|
|
types.Int32: 4,
|
|
types.Int64: 8,
|
|
types.Uint8: 1,
|
|
types.Uint16: 2,
|
|
types.Uint32: 4,
|
|
types.Uint64: 8,
|
|
types.Float32: 4,
|
|
types.Float64: 8,
|
|
types.Complex64: 8,
|
|
types.Complex128: 16,
|
|
}
|
|
|
|
// Sizeof --
|
|
func (s *gcSizes) Sizeof(T types.Type) int64 {
|
|
switch t := T.Underlying().(type) {
|
|
case *types.Basic:
|
|
k := t.Kind()
|
|
if int(k) < len(basicSizes) {
|
|
if s := basicSizes[k]; s > 0 {
|
|
return int64(s) // lint:ignore uintcast -- a byte will never exceed int64
|
|
}
|
|
}
|
|
if k == types.String {
|
|
return s.WordSize * 2
|
|
}
|
|
case *types.Array:
|
|
n := t.Len()
|
|
if n == 0 {
|
|
return 0
|
|
}
|
|
a := s.Alignof(t.Elem())
|
|
z := s.Sizeof(t.Elem())
|
|
return align(z, a)*(n-1) + z
|
|
case *types.Slice:
|
|
return s.WordSize * 3
|
|
case *types.Struct:
|
|
nf := t.NumFields()
|
|
if nf == 0 {
|
|
return 0
|
|
}
|
|
|
|
var o int64
|
|
max := int64(1)
|
|
for i := 0; i < nf; i++ {
|
|
ft := t.Field(i).Type()
|
|
a, sz := s.Alignof(ft), s.Sizeof(ft)
|
|
if a > max {
|
|
max = a
|
|
}
|
|
if i == nf-1 && sz == 0 && o != 0 {
|
|
sz = 1
|
|
}
|
|
o = align(o, a) + sz
|
|
}
|
|
return align(o, max)
|
|
case *types.Interface:
|
|
return s.WordSize * 2
|
|
}
|
|
return s.WordSize // catch-all
|
|
}
|
|
|
|
// align returns the smallest y >= x such that y % a == 0.
|
|
func align(x, a int64) int64 {
|
|
y := x + a - 1
|
|
return y - y%a
|
|
}
|