dqqpf32897 2017-11-11 11:24
浏览 96
已采纳

当C库使用不透明的结构指针时,如何解决CGO中的“写障碍错误指针”恐慌

I'm currently writing a Go wrapper around a C library. That C library uses opaque struct pointers to hide information across the interface. However, the underlying implementation stores size_t values in there. This leads to runtime errors in the resulting program. A minimum working example to reproduce the problem looks like this:

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()
}

Running this program will lead to the following error

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

Note that the errors disappear when the GC is disabled by setting the environment variable GOGC=off.

My question is which is the best way to solve or work around this problem. The library stores integer values in pointers for the sake of information hiding and this seems to confuse the GC. For obvious reasons I don't want to start messing with the library itself but rather absorb this behaviour in my wrapping layer.

My environment is Ubuntu 16.04, with gcc 5.4.0 and Go 1.9.2.

Documentation of cgo

  • 写回答

1条回答 默认 最新

  • dongqingcheng2903 2017-11-11 14:55
    关注

    I can reproduce the error for go1.8.5 and go1.9.2. I cannot reproduce the error for tip: devel +f01b928 Sat Nov 11 06:17:48 2017 +0000 (effectively 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.
    

    A Go mantra is do not ignore errors. However, you seem to assume that that the GC will gracefully ignore errors. The GC should complain loudly (go1.8.5 and go1.9.2). At worst, with undefined behavior that may vary from release to release, the GC may appear to ignore errors (go devel).

    The Go compiler sees a pointer and the Go runtime GC expects a valid pointer.

    // 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
    ", handle)
    
    slice := make([]C.Handle, 1000000)
    for i, _ := range slice {
        slice[i] = C.getInvalidPointer()
    }
    

    Use type uintptr. For example,

    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()
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法
  • ¥15 可否在不同线程中调用封装数据库操作的类
  • ¥15 微带串馈天线阵列每个阵元宽度计算
  • ¥15 keil的map文件中Image component sizes各项意思
  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据