将指针参数传递给 unsafe.Pointer:在 Go 堆中发现错误指针

问题描述 投票:0回答:1

使用中有哪些问题

方法一:

func Encode(v *float32) []byte {
    return unsafe.Slice((*byte)(unsafe.Pointer(v)), 4)
}

结束

方法2

func Encode(v float32) []byte {
    return unsafe.Slice((*byte)(unsafe.Pointer(&v)), 4)
}

两者都在 Little Endian 系统上运行。唯一的区别是 Approach 1 接受指针作为参数,而 Approach 2 接受值作为参数。

我正在调试与

相关的问题

fatal error: found bad pointer in Go heap (incorrect use of unsafe or cgo?)

found pointer to free object | bad use of unsafe.Pointer? 

我终于发现根本原因可能是由于方法1的使用。有人可以告诉我方法 1 可能存在什么问题吗?一般推荐使用方法2吗?

请注意,

float32
是功能之一。还有其他编码函数也接受
byte arrays
int8
等。

type Uuid [16]byte

func EncodeUuid(v *Uuid) []byte {
    return unsafe.Slice((*byte)(unsafe.Pointer(v)), UuidSize)
}

这里的SO答案提到原始变量可以在调用

Encode()
函数之前被GC'ed。尝试访问已释放指针指向的内存可能会导致“找到指向自由对象的指针”错误。

以下是执行过程中发现的错误日志。

错误日志1

runtime: marked free object in span 0x7fef20c4c8a8, elemsize=24 freeindex=0 (bad use of unsafe.Pointer? try -d=checkptr)
0xc14a028000 free  unmarked
0xc14a028018 free  unmarked
0xc14a028030 free  unmarked
0xc14a028048 free  unmarked
0xc14a028060 free  unmarked
0xc14a028078 free  marked   zombie
0x000000c14a028078:  0x000000c0003f2800  0x0000000000000800 
0x000000c14a028088:  0x0000000000000800 
0xc14a028090 free  unmarked
0xc14a029fc8 free  unmarked
0xc14a029fe0 free  unmarked
fatal error: found pointer to free object

goroutine 1482447 [running]:
runtime.throw({0x29b9a01?, 0xc14a028090?})
    /usr/lib/golang/src/runtime/panic.go:1047 +0x5d fp=0xc2555a2ae0 sp=0xc2555a2ab0 pc=0x44775d
runtime.(*mspan).reportZombies(0x7fef20c4c8a8)
    /usr/lib/golang/src/runtime/mgcsweep.go:788 +0x2e5 fp=0xc2555a2b60 sp=0xc2555a2ae0 pc=0x435dc5

错误日志2

runtime: pointer 0xc079e0001d to unallocated span span.base()=0xc079dfe000 span.limit=0xc079e2e010 span.state=0
runtime: found in object at *(0xc032b5c180+0x28)
object=0xc032b5c180 s.base()=0xc032b5c000 s.limit=0xc032b5e000 s.spanclass=20 s.elemsize=128 s.state=mSpanInUse
 *(object+0) = 0x0
 *(object+8) = 0x400000016
 *(object+16) = 0xffffffff00000020
 *(object+24) = 0x3a665e0
 *(object+32) = 0xc0dde3d110
 *(object+40) = 0xc079e0001d <==
 *(object+48) = 0x8000
 *(object+56) = 0x8008
 *(object+64) = 0x0
 *(object+72) = 0x0
 *(object+80) = 0x0
 *(object+88) = 0x2
 *(object+96) = 0x2000
 *(object+104) = 0x6174620
 *(object+112) = 0x101
 *(object+120) = 0x0
fatal error: found bad pointer in Go heap (incorrect use of unsafe or cgo?)

错误日志3

fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x2 addr=0x450608 pc=0x468c46]

goroutine 1202 [running]:
runtime.throw({0x3f96b81?, 0x0?})
    /usr/local/go/src/runtime/panic.go:1047 +0x5d fp=0xc006433cd0 sp=0xc006433ca0 pc=0x454c7d
runtime.sigpanic()
    /usr/local/go/src/runtime/signal_unix.go:819 +0x369 fp=0xc006433d20 sp=0xc006433cd0 pc=0x46ce09
runtime.(*waitq).enqueue(...)
    /usr/local/go/src/runtime/chan.go:766
runtime.selectgo(0xc006433fb0, 0xc006433ed8, 0x2710?, 0x0, 0x0?, 0x1)
    /usr/local/go/src/runtime/select.go:317 +0x7c6 fp=0xc006433e80 sp=0xc006433d20 pc=0x468c46

任何建议都会非常有帮助!

PS: 当GC启动时,这个问题很少发生。因此,为了有积极的GC来测试场景,我目前正在使用

GODEBUG=invalidptr=1,cgocheck=1,madvdontneed=1 GOGC=2 GOMEMLIMIT=10MiB ./my-executable
go unsafe unsafe-pointers
1个回答
0
投票

我如何解决这个问题是通过执行以下步骤

  1. 使测试具有可重复性。使用这些参数增加 GC 频率
    GODEBUG=invalidptr=1,cgocheck=1,madvdontneed=1 GOGC=2 GOMEMLIMIT=10MiB

GODEBUG=invalidptr=1,cgocheck=1,madvdontneed=1 GOGC=2 GOMEMLIMIT=10MiB ./my-service
  1. 创建一个 for 循环来运行测试并使其更具可重复性
#!/bin/bash

for i in {1..30}
do
  echo "$i"
  rm -rf ./results/xxxx
  python3 ./run.py -H127.0.0.1 -P6001 -p111 -udump -c ./cases/xxx/q1.sql
  ....
  ....
done

  1. Git 平分导致此错误的提交
git bisect start

# May 5
git bisect bad xxxxx

# May 3
git bisect good xxxx

... build and run the code and tag it as good or bad.

  1. 一旦提交导致此问题,请尝试使用以下命令运行堆配置文件并识别潜在的内存泄漏
curl -o heap.pprof "http://localhost:9876/debug/pprof/heap?seconds=30"

  1. 剩下的事情主要是运气和反复试验。祝一切顺利!
© www.soinside.com 2019 - 2024. All rights reserved.