1 // skip 2 3 // Copyright 2010 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 // Generate test of index and slice bounds checks. 8 // The actual tests are index0.go, index1.go, index2.go. 9 10 package main 11 12 import ( 13 "bufio" 14 "fmt" 15 "os" 16 "unsafe" 17 ) 18 19 const prolog = ` 20 21 package main 22 23 import ( 24 "runtime" 25 ) 26 27 type quad struct { x, y, z, w int } 28 29 const ( 30 cj = 100011 31 ci int = 100012 32 ci8 int8 = 115 33 ci16 int16 = 10016 34 ci32 int32 = 100013 35 ci64 int64 = 100014 36 ci64big int64 = 1<<31 37 ci64bigger int64 = 1<<32 38 chuge = 1<<100 39 cfgood = 2.0 40 cfbad = 2.1 41 42 cnj = -2 43 cni int = -3 44 cni8 int8 = -6 45 cni16 int16 = -7 46 cni32 int32 = -4 47 cni64 int64 = -5 48 cni64big int64 = -1<<31 49 cni64bigger int64 = -1<<32 50 cnhuge = -1<<100 51 cnfgood = -2.0 52 cnfbad = -2.1 53 ) 54 55 var j int = 100020 56 var i int = 100021 57 var i8 int8 = 126 58 var i16 int16 = 10025 59 var i32 int32 = 100022 60 var i64 int64 = 100023 61 var i64big int64 = 1<<31 62 var i64bigger int64 = 1<<32 63 var huge uint64 = 1<<64 - 1 64 var fgood float64 = 2.0 65 var fbad float64 = 2.1 66 67 var nj int = -10 68 var ni int = -11 69 var ni8 int8 = -14 70 var ni16 int16 = -15 71 var ni32 int32 = -12 72 var ni64 int64 = -13 73 var ni64big int64 = -1<<31 74 var ni64bigger int64 = -1<<32 75 var nhuge int64 = -1<<63 76 var nfgood float64 = -2.0 77 var nfbad float64 = -2.1 78 79 var si []int = make([]int, 10) 80 var ai [10]int 81 var pai *[10]int = &ai 82 83 var sq []quad = make([]quad, 10) 84 var aq [10]quad 85 var paq *[10]quad = &aq 86 87 var sib []int = make([]int, 100000) 88 var aib [100000]int 89 var paib *[100000]int = &aib 90 91 var sqb []quad = make([]quad, 100000) 92 var aqb [100000]quad 93 var paqb *[100000]quad = &aqb 94 95 type T struct { 96 si []int 97 ai [10]int 98 pai *[10]int 99 sq []quad 100 aq [10]quad 101 paq *[10]quad 102 103 sib []int 104 aib [100000]int 105 paib *[100000]int 106 sqb []quad 107 aqb [100000]quad 108 paqb *[100000]quad 109 } 110 111 var t = T{si, ai, pai, sq, aq, paq, sib, aib, paib, sqb, aqb, paqb} 112 113 var pt = &T{si, ai, pai, sq, aq, paq, sib, aib, paib, sqb, aqb, paqb} 114 115 // test that f panics 116 func test(f func(), s string) { 117 defer func() { 118 if err := recover(); err == nil { 119 _, file, line, _ := runtime.Caller(2) 120 bug() 121 print(file, ":", line, ": ", s, " did not panic\n") 122 } else if !contains(err.(error).Error(), "out of range") { 123 _, file, line, _ := runtime.Caller(2) 124 bug() 125 print(file, ":", line, ": ", s, " unexpected panic: ", err.(error).Error(), "\n") 126 } 127 }() 128 f() 129 } 130 131 func contains(x, y string) bool { 132 for i := 0; i+len(y) <= len(x); i++ { 133 if x[i:i+len(y)] == y { 134 return true 135 } 136 } 137 return false 138 } 139 140 141 var X interface{} 142 func use(y interface{}) { 143 X = y 144 } 145 146 var didBug = false 147 148 func bug() { 149 if !didBug { 150 didBug = true 151 println("BUG") 152 } 153 } 154 155 func main() { 156 ` 157 158 // pass variable set in index[012].go 159 // 0 - dynamic checks 160 // 1 - static checks of invalid constants (cannot assign to types) 161 // 2 - static checks of array bounds 162 163 func testExpr(b *bufio.Writer, expr string) { 164 if pass == 0 { 165 fmt.Fprintf(b, "\ttest(func(){use(%s)}, %q)\n", expr, expr) 166 } else { 167 fmt.Fprintf(b, "\tuse(%s) // ERROR \"index|overflow|truncated|must be integer\"\n", expr) 168 } 169 } 170 171 func main() { 172 b := bufio.NewWriter(os.Stdout) 173 174 if pass == 0 { 175 fmt.Fprint(b, "// run\n\n") 176 } else { 177 fmt.Fprint(b, "// errorcheck\n\n") 178 } 179 fmt.Fprint(b, prolog) 180 181 var choices = [][]string{ 182 // Direct value, fetch from struct, fetch from struct pointer. 183 // The last two cases get us to oindex_const_sudo in gsubr.c. 184 []string{"", "t.", "pt."}, 185 186 // Array, pointer to array, slice. 187 []string{"a", "pa", "s"}, 188 189 // Element is int, element is quad (struct). 190 // This controls whether we end up in gsubr.c (i) or cgen.c (q). 191 []string{"i", "q"}, 192 193 // Small or big len. 194 []string{"", "b"}, 195 196 // Variable or constant. 197 []string{"", "c"}, 198 199 // Positive or negative. 200 []string{"", "n"}, 201 202 // Size of index. 203 []string{"j", "i", "i8", "i16", "i32", "i64", "i64big", "i64bigger", "huge", "fgood", "fbad"}, 204 } 205 206 forall(choices, func(x []string) { 207 p, a, e, big, c, n, i := x[0], x[1], x[2], x[3], x[4], x[5], x[6] 208 209 // Pass: dynamic=0, static=1, 2. 210 // Which cases should be caught statically? 211 // Only constants, obviously. 212 // Beyond that, must be one of these: 213 // indexing into array or pointer to array 214 // negative constant 215 // large constant 216 thisPass := 0 217 if c == "c" && (a == "a" || a == "pa" || n == "n" || i == "i64big" || i == "i64bigger" || i == "huge" || i == "fbad") { 218 if i == "huge" { 219 // Due to a detail of gc's internals, 220 // the huge constant errors happen in an 221 // earlier pass than the others and inhibits 222 // the next pass from running. 223 // So run it as a separate check. 224 thisPass = 1 225 } else if a == "s" && n == "" && (i == "i64big" || i == "i64bigger") && unsafe.Sizeof(int(0)) > 4 { 226 // If int is 64 bits, these huge 227 // numbers do fit in an int, so they 228 // are not rejected at compile time. 229 thisPass = 0 230 } else { 231 thisPass = 2 232 } 233 } 234 235 pae := p + a + e + big 236 cni := c + n + i 237 238 // If we're using the big-len data, positive int8 and int16 cannot overflow. 239 if big == "b" && n == "" && (i == "i8" || i == "i16") { 240 if pass == 0 { 241 fmt.Fprintf(b, "\tuse(%s[%s])\n", pae, cni) 242 fmt.Fprintf(b, "\tuse(%s[0:%s])\n", pae, cni) 243 fmt.Fprintf(b, "\tuse(%s[1:%s])\n", pae, cni) 244 fmt.Fprintf(b, "\tuse(%s[%s:])\n", pae, cni) 245 fmt.Fprintf(b, "\tuse(%s[%s:%s])\n", pae, cni, cni) 246 } 247 return 248 } 249 250 // Float variables cannot be used as indices. 251 if c == "" && (i == "fgood" || i == "fbad") { 252 return 253 } 254 // Integral float constat is ok. 255 if c == "c" && n == "" && i == "fgood" { 256 if pass == 0 { 257 fmt.Fprintf(b, "\tuse(%s[%s])\n", pae, cni) 258 fmt.Fprintf(b, "\tuse(%s[0:%s])\n", pae, cni) 259 fmt.Fprintf(b, "\tuse(%s[1:%s])\n", pae, cni) 260 fmt.Fprintf(b, "\tuse(%s[%s:])\n", pae, cni) 261 fmt.Fprintf(b, "\tuse(%s[%s:%s])\n", pae, cni, cni) 262 } 263 return 264 } 265 266 // Only print the test case if it is appropriate for this pass. 267 if thisPass == pass { 268 // Index operation 269 testExpr(b, pae+"["+cni+"]") 270 271 // Slice operation. 272 // Low index 0 is a special case in ggen.c 273 // so test both 0 and 1. 274 testExpr(b, pae+"[0:"+cni+"]") 275 testExpr(b, pae+"[1:"+cni+"]") 276 testExpr(b, pae+"["+cni+":]") 277 testExpr(b, pae+"["+cni+":"+cni+"]") 278 } 279 }) 280 281 fmt.Fprintln(b, "}") 282 b.Flush() 283 } 284 285 func forall(choices [][]string, f func([]string)) { 286 x := make([]string, len(choices)) 287 288 var recurse func(d int) 289 recurse = func(d int) { 290 if d >= len(choices) { 291 f(x) 292 return 293 } 294 for _, x[d] = range choices[d] { 295 recurse(d + 1) 296 } 297 } 298 recurse(0) 299 } 300