cgo运行时报错"cgo argument has Go pointer to Go pointer"如何解决?
问题原因
这个报错是触发了cgo的指针传递规则:传递给C函数的Go指针,指向的内存中不能嵌套其他Go指针。
你现在的&argsProtect是Go分配的内存指针(属于Go指针),而argsProtect.plaintext字段直接引用了Go切片的底层内存地址(也是Go指针),刚好违反了这个规则,哪怕你已经把ciphertext换成C分配的内存,只要plaintext还是Go指针就会触发报错。
解决方案
需要把plaintext对应的内容也拷贝到C堆分配的内存中,替换掉原有的Go内存指针,同时记得手动释放C分配的内存避免泄漏。
完整修改代码
import "unsafe" // ... 你的其他业务逻辑 ... // 1. 处理plaintext:将Go字符串内容拷贝到C分配的内存 cPlaintext := C.CBytes([]byte(data)) defer C.free(cPlaintext) // 函数退出前释放C内存 argsProtect.plaintext = (*C.uchar)(cPlaintext) argsProtect.plaintextSize = C.uint(len(data)) const BufSize int = 256 // 2. 处理ciphertext:你的原有逻辑保留,补充释放逻辑即可 textBuffer := C.malloc(C.ulong(C.sizeof_uchar * BufSize)) defer C.free(textBuffer) // 函数退出前释放C内存 argsProtect.ciphertext = (*C.uchar)(textBuffer) argsProtect.ciphertextBufferSize = C.uint(BufSize) // 3. 调用C函数,此时不会再触发指针报错 status = int(C.VeProtect(C.VeObj(fpeProtect), &argsProtect)) // 可选:如果需要读取C返回的ciphertext内容,用C.GoBytes转回Go切片即可 // realCiphertext := C.GoBytes(unsafe.Pointer(argsProtect.ciphertext), C.int(argsProtect.ciphertextSize))
补充说明
C.CBytes是cgo提供的工具函数,会自动把Go字节切片的内容拷贝到C堆上分配的内存中,返回的是C内存的指针,完全符合cgo的传递要求- C分配的内存不受Go GC管理,必须调用
C.free手动释放,用defer可以避免遗漏释放导致内存泄漏 - 如果
argsProtect结构体还有其他指针类型的字段,也需要统一替换为C分配的内存指针,不能直接引用Go内存的地址
内容的提问来源于stack exchange,提问作者David M. Karr
相关产品推荐
相关产品推荐

