Source file test/checkbce.go

     1  // errorcheck -0 -d=ssa/check_bce/debug=3
     2  
     3  //go:build amd64 && !gcflags_noopt
     4  
     5  // Copyright 2016 The Go Authors. All rights reserved.
     6  // Use of this source code is governed by a BSD-style
     7  // license that can be found in the LICENSE file.
     8  
     9  // Test that the compiler does bounds check elimination as expected.
    10  // This avoids accidental regressions.
    11  
    12  package main
    13  
    14  import "encoding/binary"
    15  
    16  func f0(a []int) {
    17  	a[0] = 1 // ERROR "Found IsInBounds$"
    18  	a[0] = 1
    19  	a[6] = 1 // ERROR "Found IsInBounds$"
    20  	a[6] = 1
    21  	a[5] = 1
    22  	a[5] = 1
    23  }
    24  
    25  func f1(a [256]int, i int) {
    26  	var j int
    27  	useInt(a[i]) // ERROR "Found IsInBounds$"
    28  	j = i % 256
    29  	useInt(a[j]) // ERROR "Found IsInBounds$"
    30  	j = i & 255
    31  	useInt(a[j])
    32  	j = i & 17
    33  	useInt(a[j])
    34  
    35  	if 4 <= i && i < len(a) {
    36  		useInt(a[i])
    37  		useInt(a[i-1])
    38  		useInt(a[i-4])
    39  	}
    40  }
    41  
    42  func f2(a [256]int, i uint) {
    43  	useInt(a[i]) // ERROR "Found IsInBounds$"
    44  	j := i % 256
    45  	useInt(a[j])
    46  	j = i & 255
    47  	useInt(a[j])
    48  	j = i & 17
    49  	useInt(a[j])
    50  }
    51  
    52  func f2a(a [35]int, i uint8) {
    53  	useInt(a[i]) // ERROR "Found IsInBounds$"
    54  	j := i & 34
    55  	useInt(a[j])
    56  	j = i & 17
    57  	useInt(a[j])
    58  }
    59  
    60  func f2b(a [35]int, i uint16) {
    61  	useInt(a[i]) // ERROR "Found IsInBounds$"
    62  	j := i & 34
    63  	useInt(a[j])
    64  	j = i & 17
    65  	useInt(a[j])
    66  }
    67  
    68  func f2c(a [35]int, i uint32) {
    69  	useInt(a[i]) // ERROR "Found IsInBounds$"
    70  	j := i & 34
    71  	useInt(a[j])
    72  	j = i & 17
    73  	useInt(a[j])
    74  }
    75  
    76  func f3(a [256]int, i uint8) {
    77  	useInt(a[i])
    78  	useInt(a[i+10])
    79  	useInt(a[i+14])
    80  }
    81  
    82  func f4(a [27]int, i uint8) {
    83  	useInt(a[i%15])
    84  	useInt(a[i%19])
    85  	useInt(a[i%27])
    86  }
    87  
    88  func f5(a []int) {
    89  	if len(a) > 5 {
    90  		useInt(a[5])
    91  		useSlice(a[6:])
    92  		useSlice(a[:6])
    93  	}
    94  }
    95  
    96  func f6(a [32]int, b [64]int, i int) {
    97  	useInt(a[uint32(i*0x07C4ACDD)>>27])
    98  	useInt(b[uint64(i*0x07C4ACDD)>>58])
    99  	useInt(a[uint(i*0x07C4ACDD)>>59])
   100  
   101  	// The following bounds should not be removed because they can overflow.
   102  	useInt(a[uint32(i*0x106297f105d0cc86)>>26]) // ERROR "Found IsInBounds$"
   103  	useInt(b[uint64(i*0x106297f105d0cc86)>>57]) // ERROR "Found IsInBounds$"
   104  	useInt(a[int32(i*0x106297f105d0cc86)>>26])  // ERROR "Found IsInBounds$"
   105  	useInt(b[int64(i*0x106297f105d0cc86)>>57])  // ERROR "Found IsInBounds$"
   106  }
   107  
   108  func g1(a []int) {
   109  	for i := range a {
   110  		a[i] = i
   111  		useSlice(a[:i+1])
   112  		useSlice(a[:i])
   113  	}
   114  }
   115  
   116  func g2(a []int) {
   117  	useInt(a[3]) // ERROR "Found IsInBounds$"
   118  	useInt(a[2])
   119  	useInt(a[1])
   120  	useInt(a[0])
   121  }
   122  
   123  func g3(a []int) {
   124  	for i := range a[:256] { // ERROR "Found IsSliceInBounds$"
   125  		useInt(a[i]) // ERROR "Found IsInBounds$"
   126  	}
   127  	b := a[:256]
   128  	for i := range b {
   129  		useInt(b[i])
   130  	}
   131  }
   132  
   133  func g4(a [100]int) {
   134  	for i := 10; i < 50; i++ {
   135  		useInt(a[i-10])
   136  		useInt(a[i])
   137  		useInt(a[i+25])
   138  		useInt(a[i+50])
   139  
   140  		// The following are out of bounds.
   141  		if a[0] == 0xdeadbeef {
   142  			// This is a trick to prohibit sccp to optimize out the following out of bound check
   143  			continue
   144  		}
   145  		useInt(a[i-11]) // ERROR "Found IsInBounds$"
   146  		useInt(a[i+51]) // ERROR "Found IsInBounds$"
   147  	}
   148  }
   149  
   150  func decode1(data []byte) (x uint64) {
   151  	for len(data) >= 32 {
   152  		x += binary.BigEndian.Uint64(data[:8])
   153  		x += binary.BigEndian.Uint64(data[8:16])
   154  		x += binary.BigEndian.Uint64(data[16:24])
   155  		x += binary.BigEndian.Uint64(data[24:32])
   156  		data = data[32:]
   157  	}
   158  	return x
   159  }
   160  
   161  func decode2(data []byte) (x uint64) {
   162  	// TODO(rasky): this should behave like decode1 and compile to no
   163  	// boundchecks. We're currently not able to remove all of them.
   164  	for len(data) >= 32 {
   165  		x += binary.BigEndian.Uint64(data)
   166  		data = data[8:]
   167  		x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$"
   168  		data = data[8:]
   169  		x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$"
   170  		data = data[8:]
   171  		x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$"
   172  		data = data[8:]
   173  	}
   174  	return x
   175  }
   176  
   177  //go:noinline
   178  func useInt(a int) {
   179  }
   180  
   181  //go:noinline
   182  func useSlice(a []int) {
   183  }
   184  
   185  func main() {
   186  }
   187  

View as plain text