V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Nazz
V2EX  ›  程序员

golang unsafe 包修改私有属性没加偏移量会有什么隐患?

  •  
  •   Nazz · 2023-09-20 17:15:18 +08:00 · 927 次点击
    这是一个创建于 419 天前的主题,其中的信息可能已经有所发展或是发生改变。
    type Buffer struct {
    	buf      []byte
    	off      int
    	lastRead int8
    }
    
    //go:nosplit
    func BufferReset(b *bytes.Buffer, p []byte) {
    	buffer := (*Buffer)(unsafe.Pointer(b))
    	buffer.off = 0
    }
    
    11 条回复    2023-09-22 14:22:55 +08:00
    Thiece
        1
    Thiece  
       2023-09-20 17:45:30 +08:00
    如果你错误地修改了结构体的私有字段,可能会导致数据状态的不一致。例如,可能会影响缓冲区( buffer )的长度和容量,使其不匹配。

    bytes.Buffer 的实现在未来版本中发生变化也会出现问题。
    Nazz
        2
    Nazz  
    OP
       2023-09-20 17:47:28 +08:00
    @Thiece 目前没发现影响正确性(后面两个字段的值本来就是 0), 但是增加了一次 allocs 影响了性能
    Nazz
        3
    Nazz  
    OP
       2023-09-20 17:48:34 +08:00
    @Thiece 你能给出一个影响数据长度或内容的 demo 吗
    Thiece
        4
    Thiece  
       2023-09-21 10:13:26 +08:00
    ```
    package main

    import (
    "fmt"
    "unsafe"
    )

    type MyData struct {
    length int
    data int
    }

    func main() {
    data := MyData{
    length: 5,
    data: 100,
    }

    fmt.Println("Before:", data)

    // 获取 MyData 结构体的地址,并转换为通用指针
    ptr := unsafe.Pointer(&data)

    // 模拟不加偏移量的修改操作
    *(*int)(ptr) = 200

    fmt.Println("After:", data)
    }
    ```
    Nazz
        5
    Nazz  
    OP
       2023-09-21 10:27:57 +08:00
    @Thiece 不加偏移量取的就是首地址, 等价于第一个字段
    Nazz
        6
    Nazz  
    OP
       2023-09-21 10:36:01 +08:00
    @Thiece 这个例子里面,
    Nazz
        7
    Nazz  
    OP
       2023-09-21 10:36:21 +08:00
    Nazz
        8
    Nazz  
    OP
       2023-09-21 10:38:09 +08:00
    @Thiece 这个例子里面, BufferReset2 比 BufferReset1 多一次 allocs

    https://gist.github.com/lxzan/8f491e332a77ea6a049a78074799e9d7
    Thiece
        9
    Thiece  
       2023-09-21 17:13:14 +08:00   ❤️ 1
    @Nazz
    Go 语言中的结构体是将 Field 按照声明的顺序进行内存布局。
    如果没有使用 unsafe.Offsetof 之类的方法,unsafe.Pointer 获取到的地址就是该结构体的首地址。
    结构体的首地址就是其第一个字段的地址,等同于访问该结构体的第一个字段。

    BufferReset2 不仅重置了 buf 和 off ,还重置了 lastRead 。
    Nazz
        10
    Nazz  
    OP
       2023-09-21 17:23:58 +08:00
    @Thiece BufferReset2 有内存安全方面的隐患吗?
    很好奇为什么多了一次 allocs, 而且 go bench 特别慢, 但是 qps 又挺正常的
    Thiece
        11
    Thiece  
       2023-09-22 14:22:55 +08:00   ❤️ 1
    @Nazz
    在你的 github 这个代码中,BufferReset2 虽然用了 unsafe 但是操作的都是 Buffer 结构体内定义的字段,没有越界访问或对未初始化内存的操作,所以现在没有安全上的问题。
    BufferReset2 中,更改了 buf 、off 和 lastRead 字段,在 BufferReset1 中仅更改了 off 字段。可能是更多字段引起额外的内存分配导致的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1145 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 22:55 · PVG 06:55 · LAX 14:55 · JFK 17:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.