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 使用ue5插件narrative时如何切换关卡也保存叙事任务记录
  • ¥20 软件测试决策法疑问求解答
  • ¥15 win11 23H2删除推荐的项目,支持注册表等
  • ¥15 matlab 用yalmip搭建模型,cplex求解,线性化处理的方法
  • ¥15 qt6.6.3 基于百度云的语音识别 不会改
  • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单
  • ¥15 神经网络怎么把隐含层变量融合到损失函数中?
  • ¥15 lingo18勾选global solver求解使用的算法
  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行
  • ¥20 测距传感器数据手册i2c