为了账号安全,请及时绑定邮箱和手机立即绑定

存储到非 Go 内存中的 Go 指针

存储到非 Go 内存中的 Go 指针

Go
白猪掌柜的 2022-08-01 11:05:49
我有一个新手CGO问题,我想知道是否有人可以帮助我。当在 GODEBUG 设置为 cgocheck=2 的情况下运行时,我的应用程序崩溃,出现以下情况write of Go pointer 0xc0003b72c0 to non-Go memory 0x7fefa0016810fatal error: Go pointer stored into non-Go memory导致问题的代码是cArray := C.malloc(C.size_t(len(fd.Faces)) * C.size_t(unsafe.Sizeof(uintptr(0))))defer C.free(unsafe.Pointer(cArray))a := (*[1<<30 - 1]*C.struct_Box)(cArray)for index, value := range fd.GetFaceRectangles() {    box := &C.struct_Box{        left: C.int(value.Min.X),        top: C.int(value.Min.Y),        right: C.int(value.Max.X),        bottom: C.int(value.Max.Y),    }    a[index] = box}cBoxCount := C.int(len(fd.Faces))ret := C.facerec_compute_multi(rec.ptr, cImgData, cLen,  &a[0], cBoxCount)具体到这一行:a[index] = box我知道数组的内存是使用malloc在C中分配的。我试图在将C Box传递给C函数之前将其添加到数组中。解决这个问题的方法是让我用C编写一个函数,它可以接收数组和创建结构所需的项,而我在C中做那部分?我试图尽量减少对C的调用次数,所以如果我可以从Go创建数组,那就太好了。真的很难知道如何安全地将数据数组传递到C中的函数。
查看完整描述

2 回答

?
慕哥9229398

TA贡献1877条经验 获得超6个赞

您已经分配了 C 内存来容纳许多单独的指针。每个单独的指针都可以设置为单独的值。就目前而言,这很好,但是正如您所指出的,这是一个问题,因为其本身具有指向Go-memory的指针 。a[index] = boxboxC.struct_Box

我试图在将C Box传递给C函数之前将其添加到数组中。

要从字面上做到这一点,你需要一个电话。如前所述,每个实例都需要一个。C.mallocC.struct_Box

解决这个问题的方法是让我用C编写一个函数,它可以接收数组和创建结构所需的项,而我在C中做那部分?

虽然你可以尝试一下,但似乎...欠佳。

我试图尽量减少对C的调用次数,所以如果我可以从Go创建数组,那就太好了。真的很难知道如何安全地将数据数组传递到C中的函数。

C从来都不是真正安全的😀,但我怀疑你最好的选择是利用C实现“数组”的方式,这是一种穷人的切片。(或者,也许更准确地说,Go切片是一个“C数组”,做得对。请记住,切片在 Go 中作为三元素标头实现:

  • 指向存储区域底部的指针;

  • 存储区域内的当前长度;和

  • 存储区域容量

然后,它可以保存某种类型的项的一些运行时计算的n个数。C的动态“数组”以相同的方式工作,只是没有适当的切片标头的安全性。

这意味着您可以编写 C 代码(前提是您可以控制此 C 代码),以获取指向存储区域基数的指针,以及计算该区域中 n 个项目数的 or 值。此类函数的签名是:intsize_t

void f(T *base, size_t n);

其中 是项目数。(如果还想提供容量,请根据需要添加一秒钟,但如果内存具有容量,并且函数对其进行修改以包含不同数量的项目,则函数必须返回新数量的项目(即不会返回),或者本身必须通过引用或类似的东西来提供。nsize_tfvoidn

在这种情况下,如果可以安排 C 代码以获取指向 -es 中的第一个指针(而不是指向 -es 的第一个指针),则可以在单个调用中分配该指针nstruct Boxnstruct BoxC.malloc

如果您无法返工C代码,则至少会遇到两个调用。但是,您可以再次将所有es分配到一个中,并使它们全部相邻 - 即C“数组”/穷人的切片 - 然后使每个指针指向下一个:C.mallocstruct BoxC.mallocstruct Box

cArray := C.malloc(C.size_t(len(fd.Faces)) * C.size_t(unsafe.Sizeof(uintptr(0))))

defer C.free(unsafe.Pointer(cArray))

cBoxes := C.malloc(C.size_t(len(fd.Faces)) * C.size_t(unsafe.Sizeof(C.struct_Box)))

defer C.free(unsafe.Pointer(cBoxes))

a := (*[1<<30 - 1]*C.struct_Box)(cArray)

b := (*[1<<30 - 1]C.struct_Box)(cBoxes)

for index, value := range fd.GetFaceRectangles() {

    b[index] = C.struct_Box{

        left: C.int(value.Min.X),

        top: C.int(value.Min.Y),

        right: C.int(value.Max.X),

        bottom: C.int(value.Max.Y),

    }

    a[index] = &b[index]

}

cBoxCount := C.int(len(fd.Faces))

ret := C.facerec_compute_multi(rec.ptr, cImgData, cLen,  &a[0], cBoxCount)

(我试图在这里保持代码结构尽可能相似,这是未经测试的,因为我没有一些部分。


题外话:你有 和 这里的代码假设 a 的迭代次数总是 。我之所以提出这一点,是因为我做出了同样的假设,除了你的例子之外,没有任何东西可以支持它。len(fd.Faces)fd.GetFaceRectangles()for ... range fd.GetFaceRectangles()len(fd.Faces)


查看完整回答
反对 回复 2022-08-01
?
慕盖茨4494581

TA贡献1850条经验 获得超11个赞

在Slack通道上的一些帮助下,我最终得到了这个,只是直接添加结构而不是指针。


// Create an array in C

arr := C.malloc(C.size_t(len(fd.Faces)) * C.sizeof_Box)

defer C.free(unsafe.Pointer(arr))


var boxes []C.struct_Box

hdr := (*reflect.SliceHeader)(unsafe.Pointer(&boxes))

hdr.Data, hdr.Cap, hdr.Len = uintptr(arr), len(fd.Faces), len(fd.Faces)


for i, v := range fd.GetFaceRectangles() {

    boxes[i] = C.struct_Box{

        left: C.int(v.Min.X),

        top: C.int(v.Min.Y),

        right: C.int(v.Max.X),

        bottom: C.int(v.Max.Y),

    }

}

cBoxCount := C.int(len(fd.Faces))

ret := C.facerec_compute_multi(rec.ptr, cImgData, cLen, &(boxes[0]), cBoxCount)


查看完整回答
反对 回复 2022-08-01
  • 2 回答
  • 0 关注
  • 74 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信