// bad: 未判断data的长度,可导致 index out of range
func decode(data []byte) bool {
if data[0] == 'F' && data[1] == 'U' && data[2] == 'Z' && data[3] == 'Z' && data[4] == 'E' && data[5] == 'R' {
fmt.Println("Bad")
return true
}
return false
}
// bad: slice bounds out of range
func foo() {
var slice = []int{0, 1, 2, 3, 4, 5, 6}
fmt.Println(slice[:10])
}
// good: 使用data前应判断长度是否合法
func decode(data []byte) bool {
if len(data) == 6 {
if data[0] == 'F' && data[1] == 'U' && data[2] == 'Z' && data[3] == 'Z' && data[4] == 'E' && data[5] == 'R' {
fmt.Println("Good")
return true
}
}
return false
}
type Packet struct {
PackeyType uint8
PackeyVersion uint8
Data *Data
}
type Data struct {
Stat uint8
Len uint8
Buf [8]byte
}
func (p *Packet) UnmarshalBinary(b []byte) error {
if len(b) < 2 {
return io.EOF
}
p.PackeyType = b[0]
p.PackeyVersion = b[1]
// 若长度等于2,那么不会new Data
if len(b) > 2 {
p.Data = new(Data)
}
return nil
}
// bad: 未判断指针是否为nil
func main() {
packet := new(Packet)
data := make([]byte, 2)
if err := packet.UnmarshalBinary(data); err != nil {
fmt.Println("Failed to unmarshal packet")
return
}
fmt.Printf("Stat: %v\n", packet.Data.Stat)
}
// good: 判断Data指针是否为nil
func main() {
packet := new(Packet)
data := make([]byte, 2)
if err := packet.UnmarshalBinary(data); err != nil {
fmt.Println("Failed to unmarshal packet")
return
}
if packet.Data == nil {
return
}
fmt.Printf("Stat: %v\n", packet.Data.Stat)
}
在进行数字运算操作时,需要做好长度限制,防止外部输入运算导致异常:
以下场景必须严格进行长度限制:
// bad: 未限制长度,导致整数溢出
func overflow(numControlByUser int32) {
var numInt int32 = 0
numInt = numControlByUser + 1
// 对长度限制不当,导致整数溢出
fmt.Printf("%d\n", numInt)
// 使用numInt,可能导致其他错误
}
func main() {
overflow(2147483647)
}
// good
func overflow(numControlByUser int32) {
var numInt int32 = 0
numInt = numControlByUser + 1
if numInt < 0 {
fmt.Println("integer overflow")
return
}
fmt.Println("integer ok")
}
func main() {
overflow(2147483647)
}
// bad
func parse(lenControlByUser int, data []byte) {
size := lenControlByUser
// 对外部传入的size,进行长度判断以免导致panic
buffer := make([]byte, size)
copy(buffer, data)
}
// good
func parse(lenControlByUser int, data []byte) ([]byte, error) {
size := lenControlByUser
// 限制外部可控的长度大小范围
if size > 64*1024*1024 {
return nil, errors.New("value too large")
}
buffer := make([]byte, size)
copy(buffer, data)
return buffer, nil
}
// bad
func foo() {
var a, b Data
a.o = &b
b.o = &a
// 指针循环引用,SetFinalizer()无法正常调用
runtime.SetFinalizer(&a, func(d *Data) {
fmt.Printf("a %p final.\n", d)
})
runtime.SetFinalizer(&b, func(d *Data) {
fmt.Printf("b %p final.\n", d)
})
}
func main() {
for {
foo()
time.Sleep(time.Millisecond)
}
}
// bad
func foo(c chan int) {
defer close(c)
err := processBusiness()
if err != nil {
c <- 0
close(c) // 重复释放channel
return
}
c <- 1
}
// good
func foo(c chan int) {
defer close(c) // 使用defer延迟关闭channel
err := processBusiness()
if err != nil {
c <- 0
return
}
c <- 1
}
// bad: 协程没有设置退出条件
func doWaiter(name string, second int) {
for {
time.Sleep(time.Duration(second) * time.Second)
fmt.Println(name, " is ready!")
}
}
// bad: 通过unsafe操作原始指针
func unsafePointer() {
b := make([]byte, 1)
foo := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(0xfffffffe)))
fmt.Print(*foo + 1)
}
// [signal SIGSEGV: segmentation violation code=0x1 addr=0xc100068f55 pc=0x49142b]
// bad
// slice作为函数入参时包含原始数组指针
func modify(array []int) {
array[0] = 10 // 对入参slice的元素修改会影响原始数据
}
func main() {
array := []int{1, 2, 3, 4, 5}
modify(array)
fmt.Println(array) // output:[10 2 3 4 5]
}
// good
// 数组作为函数入参,而不是slice
func modify(array [5]int) {
array[0] = 10
}
func main() {
// 传入数组,注意数组与slice的区别
array := [5]int{1, 2, 3, 4, 5}
modify(array)
fmt.Println(array)
}