go - 为什么CGO的字节缓冲区可以正确读取但写入错误?

标签 go cgo

我正在使用这个库 https://github.com/billziss-gh/cgofuse ,并且需要实现一些接口(interface),其中一个如下所示:

func (self *Memfs) Write(path string, buff []byte, ofst int64, fh uint64) (n int) {
    defer trace(path, buff, ofst, fh)(&n)
    defer self.synchronize()()
    node := self.getNode(path, fh)
    if nil == node {
        return -fuse.ENOENT
    }
    endofst := ofst + int64(len(buff))
    if endofst > node.stat.Size {
        node.data = resize(node.data, endofst, true)
        node.stat.Size = endofst
    }

    fmt.Println("len(buff) = ", len(buff))  // (1)
    fmt.Println("cap(buff) = ", cap(buff))  // (2)
    fmt.Println("buff[0] = ", buff[0])      // (3)
    buff[0] = 1                             // (4)

    n = copy(node.data[ofst:endofst], buff)
    tmsp := fuse.Now()
    node.stat.Ctim = tmsp
    node.stat.Mtim = tmsp
    return
}

这是一个文件系统,写入文件时会调用Write。我在上面的代码中添加了(1),(2),(3),(4),但是(4)处出错了。错误堆栈如下:

unexpected fault address 0x116e6c60390
fatal error: fault
[signal 0xc0000005 code=0x1 addr=0x116e6c60390 pc=0xca7dad]

goroutine 17 [running, locked to thread]:
runtime.throw(0xcf373f, 0x5)
    D:/Scoop/apps/go/current/src/runtime/panic.go:1117 +0x79 fp=0xc000033bc8 sp=0xc000033b98 pc=0xc18db9
runtime.sigpanic()
    D:/Scoop/apps/go/current/src/runtime/signal_windows.go:245 +0x2d6 fp=0xc000033c20 sp=0xc000033bc8 pc=0xc2b7d6
main.(*Memfs).Write(0xc00001e400, 0xc00000a2b0, 0x9, 0x116e6c60390, 0x40000, 0x40000000, 0x0, 0x2, 0x9)
    D:/code/go/LiangFs/tool/memfs.go:310 +0x4cd fp=0xc000033de0 sp=0xc000033c20 pc=0xca7dad
github.com/billziss-gh/cgofuse/fuse.hostWrite(0x116e00d1480, 0x116e6c60390, 0x40000, 0x0, 0x1518fff7c8, 0x0)
    D:/go/pkg/mod/github.com/billziss-gh/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="83e0e4ece5f6f0e6c3f5b2adb6adb3" rel="noreferrer noopener nofollow">[email protected]</a>/fuse/host.go:255 +0x102 fp=0xc000033e60 sp=0xc000033de0 pc=0xc9c282
github.com/billziss-gh/cgofuse/fuse.go_hostWrite(...)
    D:/go/pkg/mod/github.com/billziss-gh/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="761511191003051336004758435846" rel="noreferrer noopener nofollow">[email protected]</a>/fuse/host_cgo.go:911
_cgoexp_12ef5be0dd8c_go_hostWrite(0x1518fff710)
    _cgo_gotypes.go:738 +0x59 fp=0xc000033ea0 sp=0xc000033e60 pc=0xca2919
runtime.cgocallbackg1(0xca28c0, 0x1518fff710, 0x0)
    D:/Scoop/apps/go/current/src/runtime/cgocall.go:292 +0x19a fp=0xc000033f40 sp=0xc000033ea0 pc=0xbe4c5a
runtime.cgocallbackg(0xca28c0, 0x1518fff710, 0x0)
    D:/Scoop/apps/go/current/src/runtime/cgocall.go:228 +0xfc fp=0xc000033fb8 sp=0xc000033f40 pc=0xbe49bc
runtime.cgocallback(0x0, 0x0, 0x0)
    D:/Scoop/apps/go/current/src/runtime/asm_amd64.s:788 +0xc0 fp=0xc000033fe0 sp=0xc000033fb8 pc=0xc48bc0
runtime.goexit()
    D:/Scoop/apps/go/current/src/runtime/asm_amd64.s:1371 +0x1 fp=0xc000033fe8 sp=0xc000033fe0 pc=0xc48ea1

goroutine 1 [syscall]:
github.com/billziss-gh/cgofuse/fuse._Cfunc_hostMount(0x3, 0xc00001e420, 0x116e0316540, 0x0)
    _cgo_gotypes.go:502 +0x4f
github.com/billziss-gh/cgofuse/fuse.c_hostMount.func1(0xc000000003, 0xc00001e420, 0x116e0316540, 0x116e0316540)
    D:/go/pkg/mod/github.com/billziss-gh/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b3d0d4dcd5c6c0d6f3c5829d869d83" rel="noreferrer noopener nofollow">[email protected]</a>/fuse/host_cgo.go:820 +0x8c
github.com/billziss-gh/cgofuse/fuse.c_hostMount(0xc000000003, 0xc00001e420, 0x116e0316540, 0xb)
    D:/go/pkg/mod/github.com/billziss-gh/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f99a9e969f8c8a9cb98fc8d7ccd7c9" rel="noreferrer noopener nofollow">[email protected]</a>/fuse/host_cgo.go:820 +0x45
github.com/billziss-gh/cgofuse/fuse.(*FileSystemHost).Mount(0xc00003e040, 0xcf4632, 0xb, 0xc000034210, 0x0, 0x0, 0x1ffffff00)
    D:/go/pkg/mod/github.com/billziss-gh/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="462521292033352306307768736876" rel="noreferrer noopener nofollow">[email protected]</a>/fuse/host.go:704 +0x413
main.main()
    D:/code/go/LiangFs/tool/memfs.go:594 +0xce
len(buff) =  262144
cap(buff) =  1073741824
buff[0] =  97

buff的内容全是97,因为我将以下文件复制到这个文件系统中: enter image description here

代码来自库https://github.com/billziss-gh/cgofuse/blob/master/examples/memfs/memfs.go中的示例,我只是添加了上面提到的(1)、(2)、(3)、(4)。

我的操作系统是windows 10,go版本是go1.16.7 windows/amd64。

为什么分配 slice 元素会出错?是因为图书馆使用了CGO吗?

最佳答案

我是 WinFsp 和 cgofuse 的作者,可以解释这里发生的事情。

您在Write中收到的缓冲区应始终被视为只读缓冲区。尝试写入此缓冲区可能会导致访问冲突。这是设计使然。

当应用程序发出WriteFile请求时,WinFsp内核模式驱动程序必须以某种方式将数据从应用程序传输到用户模式文件系统。驱动程序有几种不同的策略来执行此操作,在某些情况下它会选择零复制技术:它将应用程序缓冲区直接映射到用户模式文件系统的地址空间,从而避免昂贵的内存复制。 p>

Write的情况下,此零拷贝映射将始终是只读的,以避免用户模式意外或恶意写入应用程序的WriteFile 缓冲区。 (另请注意,当 WinFsp 驱动程序设置此映射时,它会确保数据不会意外地从应用程序泄漏到用户模式文件系统中。)

关于go - 为什么CGO的字节缓冲区可以正确读取但写入错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69333916/

相关文章:

go - 使用 CGO 动态选择正确的操作系统和处理器架构

session - 在 Golang 中跟踪在线用户

go - channel 和并行混淆

sqlite - 为什么包含两个基于 cgo 的库时会得到 "duplicate symbol reference"?

python - 如何从go返回错误字符串到python

go - Confluence kafka go 软件包与 ubuntu 22.04 兼容吗?

go - 从共享库访问函数时出现内存不足 panic

go - 如何使用godoc正确生成文档?

go - Golang Ginkgo BeforeSuite 没有输出

go - 自定义 OpenCensus 指标未出现在 Stackdriver 上