# Go1.7里面的BCE(跳跃检测排除)(译文)

astaxie · · 1269 次点击 · · 开始浏览

### 例子1

// example1.gopackage mainfunc f1(s []int) {
_ = s[0] // line 5: bounds check
_ = s[1] // line 6: bounds check
_ = s[2] // line 7: bounds check }func f2(s []int) {
_ = s[2] // line 11: bounds check
_ = s[1] // line 12: bounds check eliminatd!
_ = s[0] // line 13: bounds check eliminatd!}func f3(s []int, index int) {
_ = s[index] // line 17: bounds check
_ = s[index] // line 18: bounds check eliminatd!}func f4(a [5]int) {
_ = a[4] // line 22: bounds check eliminatd!}func main() {}
\$ go build -gcflags="-d=ssa/check_bce/debug=1" example1.go
# command-line-arguments
./11.go:5: Found IsInBounds
./11.go:6: Found IsInBounds
./11.go:7: Found IsInBounds
./11.go:11: Found IsInBounds
./11.go:17: Found IsInBounds

Go 1.7 的编辑器也正确的分析出来了f4函数里面的唯一的一行(22行)也是安全的。

### 例子2

// example2.go
package main

func f5(s []int) {
for i := range s {
_ = s[i]
_ = s[i:len(s)]
_ = s[:i+1]
}
}

func f6(s []int) {
for i := 0; i < len(s); i ++ {
_ = s[i]
_ = s[i:len(s)]
_ = s[:i+1]
}
}

func f7(s []int) {
for i := len(s) - 1; i >= 0; i -- {
_ = s[i] // line 22: bounds check
_ = s[i:len(s)]
}
}

func f8(s []int, index int) {
if index >= 0 && index < len(s) {
_ = s[index]
_ = s[index:len(s)]
}
}

func f9(s []int) {
if len(s) > 2 {
_, _, _ = s[0], s[1], s[2]
}
}

func main() {}
\$ go build -gcflags="-d=ssa/check_bce/debug=1" example2.go
# command-line-arguments
./11.go:22: Found IsInBounds

Go 1.7 编译器是如此的聪明，它精确的做出决定说：在f5和f6里面所有的代码都是安全的

### 例子3

// example3.go
package main

import "math/rand"

func fa() {
s := []int{0, 1, 2, 3, 4, 5, 6}
index := rand.Intn(7)
_ = s[:index] // line 9: bounds check
_ = s[index:] // line 10: bounds check eliminatd!
}

func fb(s []int, index int) {
_ = s[:index] // line 14: bounds check
_ = s[index:] // line 15: bounds check // not smart enough or a bug?
}

func fc() {
s := []int{0, 1, 2, 3, 4, 5, 6}
s = s[:4]
index := rand.Intn(7)
_ = s[:index] // line 22: bounds check
_ = s[index:] // line 23: bounds check
}

func main() {}
\$ go build -gcflags="-d=ssa/check_bce/debug=1" example3.go
# command-line-arguments
./11.go:9: Found IsSliceInBounds
./11.go:14: Found IsSliceInBounds
./11.go:15: Found IsSliceInBounds
./11.go:22: Found IsSliceInBounds
./11.go:23: Found IsSliceInBounds

package main

func main() {
s0 := make([]int, 5, 10) // len(s0) == 5, cap(s0) == 10

index := 8

// In golang, for the subslice syntax s[a:b],
// the valid rage for a is [0, len(s)],
// the valid rage for b is [a, cap(s)].

// So, this line is no problem.
_ = s0[:index]
// But, above line is safe can't assure the following line is also safe.
// In fact, it will panic.
_ = s0[index:] // panic: runtime error: slice bounds out of range
}

。这就是为什么在例子3里面fb和fc里面的代码还需要进行越界检查。

Go 1.7 编译器在函数fa里面成功的检测到了 len(s) == cap(s)。太棒了！Golang Team!

### 例子4

// example4.go
package main

import "math/rand"

func fa2() {
s := []int{0, 1, 2, 3, 4, 5, 6}
index := rand.Intn(7)
_ = s[index:] // line 9: bounds check
_ = s[:index] // line 10: bounds check eliminatd!
}

func fb2(s []int, index int) {
_ = s[index:] // line 14: bounds check
_ = s[:index] // line 15: bounds check // not smart enough?
}

func fc2() {
s := []int{0, 1, 2, 3, 4, 5, 6}
s = s[:4]
index := rand.Intn(7)
_ = s[index:] // line 22: bounds check
_ = s[:index] // line 23: bounds check eliminatd!
}

func main() {}
\$ go build -gcflags="-d=ssa/check_bce/debug=1" example4.go
# command-line-arguments
./11.go:9: Found IsSliceInBounds
./11.go:14: Found IsSliceInBounds
./11.go:15: Found IsSliceInBounds
./11.go:22: Found IsSliceInBounds

#### 例子5

// example5.go
package main

func fd(is []int, bs []byte) {
if len(is) >= 256 {
for _, n := range bs {
_ = is[n] // line 7: bounds check, not smart enough.
}
}
}

func fd2(is []int, bs []byte) {
if len(is) >= 256 {
is = is[:256] // line 14: bounds check. A hint for the compiler.
for _, n := range bs {
_ = is[n] // line 16: bounds check eliminatd!
}
}
}

func fe(isa []int, isb []int) {
if len(isa) > 0xFFF {
for _, n := range isb {
_ = isa[n & 0xFFF] // line 24: bounds check, not smart enough.
}
}
}

func fe2(isa []int, isb []int) {
if len(isa) > 0xFFF {
isa = isa[:0xFFF+1] // line 31: bounds check. A hint for the compiler.
for _, n := range isb {
_ = isa[n & 0xFFF] // line 33: bounds check eliminatd!
}
}
}

func ff(s []int) []int {
s2 := make([]int, len(s))
for i := range s {
s2[i] = -s[i] // line 41: bounds check, not smart enough.
}
return s2
}

func ff2(s []int) []int {
s2 := make([]int, len(s))
s2 = s2[:len(s)] // line 48: bounds check. A hint for the compiler.
for i := range s {
s2[i] = -s[i] // line 50: bounds check eliminatd!
}
return s2
}

func main() {}
\$ go build -gcflags="-d=ssa/check_bce/debug=1" example5.go
# command-line-arguments
./11.go:7: Found IsInBounds
./11.go:14: Found IsSliceInBounds
./11.go:24: Found IsInBounds
./11.go:31: Found IsSliceInBounds
./11.go:41: Found IsInBounds
./11.go:48: Found IsSliceInBounds

### 参考文献

Go社区：https://gocn.io

0 回复

• 请尽量让自己的回复能够对别人有帮助
• 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
• 支持 @ 本站用户；支持表情（输入 : 提示），见 Emoji cheat sheet
• 图片支持拖拽、截图粘贴等方式上传

### 例子1

// example1.gopackage mainfunc f1(s []int) {
_ = s[0] // line 5: bounds check
_ = s[1] // line 6: bounds check
_ = s[2] // line 7: bounds check }func f2(s []int) {
_ = s[2] // line 11: bounds check
_ = s[1] // line 12: bounds check eliminatd!
_ = s[0] // line 13: bounds check eliminatd!}func f3(s []int, index int) {
_ = s[index] // line 17: bounds check
_ = s[index] // line 18: bounds check eliminatd!}func f4(a [5]int) {
_ = a[4] // line 22: bounds check eliminatd!}func main() {}
\$ go build -gcflags="-d=ssa/check_bce/debug=1" example1.go
# command-line-arguments
./11.go:5: Found IsInBounds
./11.go:6: Found IsInBounds
./11.go:7: Found IsInBounds
./11.go:11: Found IsInBounds
./11.go:17: Found IsInBounds

Go 1.7 的编辑器也正确的分析出来了f4函数里面的唯一的一行(22行)也是安全的。

### 例子2

// example2.go
package main

func f5(s []int) {
for i := range s {
_ = s[i]
_ = s[i:len(s)]
_ = s[:i+1]
}
}

func f6(s []int) {
for i := 0; i < len(s); i ++ {
_ = s[i]
_ = s[i:len(s)]
_ = s[:i+1]
}
}

func f7(s []int) {
for i := len(s) - 1; i >= 0; i -- {
_ = s[i] // line 22: bounds check
_ = s[i:len(s)]
}
}

func f8(s []int, index int) {
if index >= 0 && index < len(s) {
_ = s[index]
_ = s[index:len(s)]
}
}

func f9(s []int) {
if len(s) > 2 {
_, _, _ = s[0], s[1], s[2]
}
}

func main() {}
\$ go build -gcflags="-d=ssa/check_bce/debug=1" example2.go
# command-line-arguments
./11.go:22: Found IsInBounds

Go 1.7 编译器是如此的聪明，它精确的做出决定说：在f5和f6里面所有的代码都是安全的

### 例子3

// example3.go
package main

import "math/rand"

func fa() {
s := []int{0, 1, 2, 3, 4, 5, 6}
index := rand.Intn(7)
_ = s[:index] // line 9: bounds check
_ = s[index:] // line 10: bounds check eliminatd!
}

func fb(s []int, index int) {
_ = s[:index] // line 14: bounds check
_ = s[index:] // line 15: bounds check // not smart enough or a bug?
}

func fc() {
s := []int{0, 1, 2, 3, 4, 5, 6}
s = s[:4]
index := rand.Intn(7)
_ = s[:index] // line 22: bounds check
_ = s[index:] // line 23: bounds check
}

func main() {}
\$ go build -gcflags="-d=ssa/check_bce/debug=1" example3.go
# command-line-arguments
./11.go:9: Found IsSliceInBounds
./11.go:14: Found IsSliceInBounds
./11.go:15: Found IsSliceInBounds
./11.go:22: Found IsSliceInBounds
./11.go:23: Found IsSliceInBounds

package main

func main() {
s0 := make([]int, 5, 10) // len(s0) == 5, cap(s0) == 10

index := 8

// In golang, for the subslice syntax s[a:b],
// the valid rage for a is [0, len(s)],
// the valid rage for b is [a, cap(s)].

// So, this line is no problem.
_ = s0[:index]
// But, above line is safe can't assure the following line is also safe.
// In fact, it will panic.
_ = s0[index:] // panic: runtime error: slice bounds out of range
}

。这就是为什么在例子3里面fb和fc里面的代码还需要进行越界检查。

Go 1.7 编译器在函数fa里面成功的检测到了 len(s) == cap(s)。太棒了！Golang Team!

### 例子4

// example4.go
package main

import "math/rand"

func fa2() {
s := []int{0, 1, 2, 3, 4, 5, 6}
index := rand.Intn(7)
_ = s[index:] // line 9: bounds check
_ = s[:index] // line 10: bounds check eliminatd!
}

func fb2(s []int, index int) {
_ = s[index:] // line 14: bounds check
_ = s[:index] // line 15: bounds check // not smart enough?
}

func fc2() {
s := []int{0, 1, 2, 3, 4, 5, 6}
s = s[:4]
index := rand.Intn(7)
_ = s[index:] // line 22: bounds check
_ = s[:index] // line 23: bounds check eliminatd!
}

func main() {}
\$ go build -gcflags="-d=ssa/check_bce/debug=1" example4.go
# command-line-arguments
./11.go:9: Found IsSliceInBounds
./11.go:14: Found IsSliceInBounds
./11.go:15: Found IsSliceInBounds
./11.go:22: Found IsSliceInBounds

#### 例子5

// example5.go
package main

func fd(is []int, bs []byte) {
if len(is) >= 256 {
for _, n := range bs {
_ = is[n] // line 7: bounds check, not smart enough.
}
}
}

func fd2(is []int, bs []byte) {
if len(is) >= 256 {
is = is[:256] // line 14: bounds check. A hint for the compiler.
for _, n := range bs {
_ = is[n] // line 16: bounds check eliminatd!
}
}
}

func fe(isa []int, isb []int) {
if len(isa) > 0xFFF {
for _, n := range isb {
_ = isa[n & 0xFFF] // line 24: bounds check, not smart enough.
}
}
}

func fe2(isa []int, isb []int) {
if len(isa) > 0xFFF {
isa = isa[:0xFFF+1] // line 31: bounds check. A hint for the compiler.
for _, n := range isb {
_ = isa[n & 0xFFF] // line 33: bounds check eliminatd!
}
}
}

func ff(s []int) []int {
s2 := make([]int, len(s))
for i := range s {
s2[i] = -s[i] // line 41: bounds check, not smart enough.
}
return s2
}

func ff2(s []int) []int {
s2 := make([]int, len(s))
s2 = s2[:len(s)] // line 48: bounds check. A hint for the compiler.
for i := range s {
s2[i] = -s[i] // line 50: bounds check eliminatd!
}
return s2
}

func main() {}
\$ go build -gcflags="-d=ssa/check_bce/debug=1" example5.go
# command-line-arguments
./11.go:7: Found IsInBounds
./11.go:14: Found IsSliceInBounds
./11.go:24: Found IsInBounds
./11.go:31: Found IsSliceInBounds
./11.go:41: Found IsInBounds
./11.go:48: Found IsSliceInBounds

### 参考文献

Go社区：https://gocn.io