Go 指针存储到非 Go 内存中
Go pointer stored into non-Go memory
我有一个新手 CGO 问题,我想知道是否有人可以帮助我。当 运行 GODEBUG 设置为 cgocheck=2 时,我的应用程序崩溃并显示以下内容
write of Go pointer 0xc0003b72c0 to non-Go memory 0x7fefa0016810
fatal 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
我知道数组的内存是在 C 语言中使用 malloc 分配的。我试图在将 C Box 传递给 C 函数之前将其添加到数组中。解决这个问题的方法是让我在 C 中编写一个函数,该函数可以接收数组和创建结构所需的项目,而我在 C 中执行该部分吗?我正在尝试最大程度地减少对 C 的调用次数,因此如果我可以从 Go 创建数组那就太好了。真的在为如何安全地将数据数组传递给 C 中的函数而苦苦挣扎。
您已经分配了 C 内存来保存许多单独的指针。每个单独的指针都可以设置为单独的值。就目前而言这很好,但正如您所指出的,a[index] = box
是一个问题,因为 box
本身包含一个指向 Go-memory C.struct_Box
.
的指针
I'm trying to add C Box to the array before passing it to a C function.
要做到这一点,您需要一个 C.malloc
调用。如所写,每个 C.struct_Box
个实例需要一个。
Would the fix for this be for me to write a function in C which can receive the array and the items needed to create the struct and I do that part in C instead?
虽然您可以尝试这样做,但似乎...不是最理想的。
I'm trying to minimise the number of calls to C so If I can create the array from Go that would be great. Really struggling with how to pass an array of data through to a function in C safely.
C 从来都不是真正的 安全 但我怀疑你最好的选择是利用 C 实现“数组”的方式,这是一种穷人的切片. (或者,也许更准确地说,一个 Go 切片是一个正确完成的“C 数组”。)请记住,一个切片在 Go 中被实现为一个三元素头:
- 指向存储区基址的指针;
- 当前存储区长度;和
- 存储区容量
然后可以容纳一些 运行 时间计算的某种类型的项目数 n。 C 的动态“数组”以相同的方式工作,只是没有适当的切片头的安全性。
这意味着你可以编写你的 C 代码——提供 你可以控制 这个 C 代码——获取一个指针到存储区域的底部,以及计算该区域中项目数量 n 的 int
或 size_t
值。这样一个函数的签名是:
void f(T *base, size_t n);
其中 n
是项目数。 (如果合适,添加第二个 size_t
,如果你也想提供容量,但如果内存有容量,并且函数修改它以包含不同数量的项目,那么函数必须 return 新的项目数量——即 f
不会是 void
——或者 n
本身必须通过引用或类似的方式提供。)
在这种情况下,如果您可以安排 C 代码将指针指向 n
struct Box
-es 的第一个(而不是 n
指向 struct Box
-es) 的指针,您可以在单个 C.malloc
调用中分配它。
如果您无法重写 C 代码,则至少需要两次 C.malloc
调用。但是,您可以再次将所有 struct Box
分配到一个 C.malloc
中,并使它们都相邻——即 C“数组”/穷人的切片——然后使每个指针指向下一个 struct 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)
(我在这里尽量保持代码结构相似,这是未经测试的,因为我没有一些部分。)
旁白:你有 len(fd.Faces)
和 fd.GetFaceRectangles()
,这里的代码假设 for ... range fd.GetFaceRectangles()
的迭代次数总是 len(fd.Faces)
。我这么说是因为我做了同样的假设,除了你的例子之外没有任何证据支持它。
在 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)
我有一个新手 CGO 问题,我想知道是否有人可以帮助我。当 运行 GODEBUG 设置为 cgocheck=2 时,我的应用程序崩溃并显示以下内容
write of Go pointer 0xc0003b72c0 to non-Go memory 0x7fefa0016810
fatal 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
我知道数组的内存是在 C 语言中使用 malloc 分配的。我试图在将 C Box 传递给 C 函数之前将其添加到数组中。解决这个问题的方法是让我在 C 中编写一个函数,该函数可以接收数组和创建结构所需的项目,而我在 C 中执行该部分吗?我正在尝试最大程度地减少对 C 的调用次数,因此如果我可以从 Go 创建数组那就太好了。真的在为如何安全地将数据数组传递给 C 中的函数而苦苦挣扎。
您已经分配了 C 内存来保存许多单独的指针。每个单独的指针都可以设置为单独的值。就目前而言这很好,但正如您所指出的,a[index] = box
是一个问题,因为 box
本身包含一个指向 Go-memory C.struct_Box
.
I'm trying to add C Box to the array before passing it to a C function.
要做到这一点,您需要一个 C.malloc
调用。如所写,每个 C.struct_Box
个实例需要一个。
Would the fix for this be for me to write a function in C which can receive the array and the items needed to create the struct and I do that part in C instead?
虽然您可以尝试这样做,但似乎...不是最理想的。
I'm trying to minimise the number of calls to C so If I can create the array from Go that would be great. Really struggling with how to pass an array of data through to a function in C safely.
C 从来都不是真正的 安全 但我怀疑你最好的选择是利用 C 实现“数组”的方式,这是一种穷人的切片. (或者,也许更准确地说,一个 Go 切片是一个正确完成的“C 数组”。)请记住,一个切片在 Go 中被实现为一个三元素头:
- 指向存储区基址的指针;
- 当前存储区长度;和
- 存储区容量
然后可以容纳一些 运行 时间计算的某种类型的项目数 n。 C 的动态“数组”以相同的方式工作,只是没有适当的切片头的安全性。
这意味着你可以编写你的 C 代码——提供 你可以控制 这个 C 代码——获取一个指针到存储区域的底部,以及计算该区域中项目数量 n 的 int
或 size_t
值。这样一个函数的签名是:
void f(T *base, size_t n);
其中 n
是项目数。 (如果合适,添加第二个 size_t
,如果你也想提供容量,但如果内存有容量,并且函数修改它以包含不同数量的项目,那么函数必须 return 新的项目数量——即 f
不会是 void
——或者 n
本身必须通过引用或类似的方式提供。)
在这种情况下,如果您可以安排 C 代码将指针指向 n
struct Box
-es 的第一个(而不是 n
指向 struct Box
-es) 的指针,您可以在单个 C.malloc
调用中分配它。
如果您无法重写 C 代码,则至少需要两次 C.malloc
调用。但是,您可以再次将所有 struct Box
分配到一个 C.malloc
中,并使它们都相邻——即 C“数组”/穷人的切片——然后使每个指针指向下一个 struct 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)
(我在这里尽量保持代码结构相似,这是未经测试的,因为我没有一些部分。)
旁白:你有 len(fd.Faces)
和 fd.GetFaceRectangles()
,这里的代码假设 for ... range fd.GetFaceRectangles()
的迭代次数总是 len(fd.Faces)
。我这么说是因为我做了同样的假设,除了你的例子之外没有任何证据支持它。
在 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)