gpt4 book ai didi

c - 当C库使用不透明结构指针时,如何解决cgo中的 "bad pointer in write barrier"panic

转载 作者:IT王子 更新时间:2023-10-29 00:45:59 24 4
gpt4 key购买 nike

我目前正在围绕 C 库编写 Go 包装器。该 C 库使用不透明的结构指针来隐藏界面中的信息。但是,底层实现将 size_t 值存储在那里。这会导致生成的程序出现运行时错误。重现问题的最小工作示例如下所示:

main.go:

package main

/*
#include "stddef.h"
// Create an opaque type to hide the details of the underlying data structure.
typedef struct HandlePrivate *Handle;

// In reality, the implementation uses a type derived from size_t for the Handle.
Handle getInvalidPointer() {
size_t actualHandle = 1;
return (Handle) actualHandle;
}
*/
import "C"

// Create a temporary slice containing invalid pointers.
// The idea is that the local variable slice can be garbage collected at the end of the function call.
// When the slice is scanned for linked objects, the GC comes across the invalid pointers.
func getTempSlice() {
slice := make([]C.Handle, 1000000)
for i, _ := range slice {
slice[i] = C.getInvalidPointer()
}
}

func main() {
getTempSlice()
}

运行这个程序会出现如下错误

runtime: writebarrierptr *0xc42006c000 = 0x1
fatal error: bad pointer in write barrier
[...stack trace omitted...]

请注意,当通过设置环境变量 GOGC=off 禁用 GC 时,错误会消失。

我的问题是解决或解决此问题的最佳方法是什么。为了隐藏信息,库将整数值存储在指针中,这似乎混淆了 GC。出于明显的原因,我不想开始弄乱库本身,而是在我的包装层中吸收这种行为。

我的环境是 Ubuntu 16.04,gcc 5.4.0 和 Go 1.9.2。

Documentation of cgo

最佳答案

我可以重现 go1.8.5go1.9.2 的错误。我无法重现提示的错误:devel +f01b928 Sat Nov 11 06:17:48 2017 +0000(实际上是 go1.10alpha)。


// Create a temporary slice containing invalid pointers.
// The idea is that the local variable slice can be garbage collected at the end of the function call.
// When the slice is scanned for linked objects, the GC comes across the invalid pointers.

Go 的格言是不要忽略错误。但是,您似乎假设 GC 会优雅地忽略错误。 GC 应该大声提示(go1.8.5go1.9.2)。在最坏的情况下,由于未定义的行为可能因版本而异,GC 可能会忽略错误 (go devel)。

Go 编译器看到一个指针,Go 运行时 GC 需要一个有效的指针。

// go tool cgo
// type _Ctype_Handle *_Ctype_struct_HandlePrivate
// var handle _Ctype_Handle
var handle C.Handle
// main._Ctype_Handle <nil> 0x0
fmt.Fprintf(os.Stderr, "%[1]T %[1]v %[1]p\n", handle)

slice := make([]C.Handle, 1000000)
for i, _ := range slice {
slice[i] = C.getInvalidPointer()
}

使用类型uintptr。例如,

package main

import "unsafe"

/*
#include "stddef.h"
// Create an opaque type to hide the details of the underlying data structure.
typedef struct HandlePrivate *Handle;

// In reality, the implementation uses a type derived from size_t for the Handle.
Handle getInvalidPointer() {
size_t actualHandle = 1;
return (Handle) actualHandle;
}
*/
import "C"

// Create a temporary slice of C pointers as Go integer type uintptr.
func getTempSlice() {
slice := make([]uintptr, 1000000)
for i, _ := range slice {
slice[i] = uintptr(unsafe.Pointer(C.getInvalidPointer()))
}
}

func main() {
getTempSlice()
}

关于c - 当C库使用不透明结构指针时,如何解决cgo中的 "bad pointer in write barrier"panic,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47237363/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com