dsm0688 2016-07-24 05:02
浏览 109
已采纳

是否有必要进行早期边界检查以确保Golang中写入的安全性?

If you look at "encoding/binary" package:

func (littleEndian) Uint64(b []byte) uint64 {
    _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
    return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
        uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
}

func (littleEndian) PutUint64(b []byte, v uint64) {
    _ = b[7] // early bounds check to guarantee safety of writes below
    b[0] = byte(v)
    b[1] = byte(v >> 8)
    b[2] = byte(v >> 16)
    b[3] = byte(v >> 24)
    b[4] = byte(v >> 32)
    b[5] = byte(v >> 40)
    b[6] = byte(v >> 48)
    b[7] = byte(v >> 56)
}

You will see:

_ = b[7] // early bounds check to guarantee safety of writes below

Now consider this sample code A (see comment):

package main

import "fmt"

func main() {
    b := []byte{0, 1, 2, 3, 4, 5, 6}
    var v uint64 = 0x0807060504030201

    b[0] = byte(v)
    b[1] = byte(v >> 8)
    b[2] = byte(v >> 16)
    b[3] = byte(v >> 24)
    b[4] = byte(v >> 32)
    b[5] = byte(v >> 40)
    b[6] = byte(v >> 48)
    b[7] = byte(v >> 56) // panic: runtime error: index out of range

    fmt.Println(b)
}

And this sample code B (see comment):

package main

import "fmt"

func main() {
    b := []byte{0, 1, 2, 3, 4, 5, 6}
    var v uint64 = 0x0807060504030201

    b[7] = byte(v >> 56) // panic: runtime error: index out of range
    b[6] = byte(v >> 48)
    b[5] = byte(v >> 40)
    b[4] = byte(v >> 32)
    b[3] = byte(v >> 24)
    b[2] = byte(v >> 16)
    b[1] = byte(v >> 8)
    b[0] = byte(v)

    fmt.Println(b)
}

And sample code C:

package main

import "fmt"

func main() {
    b := []byte{0, 1, 2, 3, 4, 5, 6}
    var v uint64 = 0x0807060504030201

    _ = b[7] // early bounds check to guarantee safety of writes below

    b[0] = byte(v)
    b[1] = byte(v >> 8)
    b[2] = byte(v >> 16)
    b[3] = byte(v >> 24)
    b[4] = byte(v >> 32)
    b[5] = byte(v >> 40)
    b[6] = byte(v >> 48)
    b[7] = byte(v >> 56)

    fmt.Println(b)
}

So I have two questions:
Q1: Is it necessary to early bounds check to guarantee safety of writes in Golang?
Q2: For early bounds check to guarantee safety of writes which Sample Code is more concise and performance optimized (speed), sample code A, B, C or ... ?

A2: I think B : because it is concise and do early bounds check , isn't it?

  • 写回答

2条回答 默认 最新

  • duanbin198788 2016-07-24 05:46
    关注

    Q1: is it necessary to early bounds check to guarantee safety of writes in Golang?

    The answer here is "yes and no". In general, "no", you do not normally have to insert bounds checks in Go because the compiler inserts them for you (that's why your examples panic when you try to access a memory location beyond the length of the slice). However, if you're doing multiple writes like the example given then, "yes", you'll need to insert an early bounds check like the example provided to ensure that you don't have only some of the writes succeed, putting you in a bad state (or refactor as you did in example B so that the first write is to the largest array, ensuring that the panic will happen before any writes can succeed).

    However, this isn't so much a "go problem" as it is a generic class of bug. If you don't do bounds checking (or don't start with the highest index if it's a language that enforces bounds checking itself like Go) in any language, the writes aren't safe. It also very heavily depends on the situation; in the example from the standard library you posted, the user bounds check is necessary. In the second example you posted, however, the user bounds check is not necessary because the code can be written like B where the compiler inserts the bounds check on the first line.

    Q2: for early bounds check to guarantee safety of writes which Sample Code is more concise and performance optimized (speed), sample code A, B, C or ... ?

    A2: I think B : because it is concise and do early bounds check , isn't it?

    You are correct. In B the compiler will insert a bounds check on the first write, protecting the rest of the writes. Because you are indexing the slice with a constant (7, 6, … 0) the compiler can elide the bounds check from the rest of the writes since it can guarantee that they are safe.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 表达式必须是可修改的左值
  • ¥15 如何绘制动力学系统的相图
  • ¥15 对接wps接口实现获取元数据
  • ¥20 给自己本科IT专业毕业的妹m找个实习工作
  • ¥15 用友U8:向一个无法连接的网络尝试了一个套接字操作,如何解决?
  • ¥30 我的代码按理说完成了模型的搭建、训练、验证测试等工作(标签-网络|关键词-变化检测)
  • ¥50 mac mini外接显示器 画质字体模糊
  • ¥15 TLS1.2协议通信解密
  • ¥40 图书信息管理系统程序编写
  • ¥20 Qcustomplot缩小曲线形状问题