为什么来自CGO的字节缓冲区可以正确读取,但写入时出错?

huangapple go评论83阅读模式
英文:

Why a byte buffer from CGO can reads correctly but write fault?

问题

我正在使用这个库https://github.com/billziss-gh/cgofuse,并且需要实现一些接口,其中一个接口看起来像这样:

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

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

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

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

为什么赋值一个切片元素会出错?是因为该库使用了CGO吗?

英文:

I am using this library https://github.com/billziss-gh/cgofuse, and some interfaces need to be implemented,one of them looks like this:

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
}

This is a file system, Write is called when writing to a file. I added (1), (2), (3), (4) in the above code, but it was wrong at (4). The error stack is as follows:

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/cgofuse@v1.5.0/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/cgofuse@v1.5.0/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/cgofuse@v1.5.0/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/cgofuse@v1.5.0/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/cgofuse@v1.5.0/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

the content of buff is all 97, becasue I copy the following file to this file system:
为什么来自CGO的字节缓冲区可以正确读取,但写入时出错?

The code comes from the example in the library https://github.com/billziss-gh/cgofuse/blob/master/examples/memfs/memfs.go , I just added the (1), (2), (3), (4) mentioned above.

My os is windows 10, go version is go1.16.7 windows/amd64.

Why does assigning a slice element make a mistake? Is it because the library uses CGO?

答案1

得分: 3

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

Write中接收到的缓冲区应该始终被视为只读缓冲区。尝试向该缓冲区写入数据可能导致访问冲突。这是设计上的考虑。

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

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

英文:

I am the author of both WinFsp and cgofuse and can explain what is happening here.

The buffer that you receive in Write should always be treated as a read-only buffer. Attempting to write into this buffer may result in an access violation. This is by design.

When an application issues a WriteFile request, the WinFsp kernel mode driver has to somehow transfer the data from the application to the user mode file system. The driver has a few different strategies for doing so and under certain circumstances it will choose a zero-copy technique: it will map the application buffer directly into the address space of the user mode file system, thus avoiding an expensive memory copy.

In the case of Write this zero-copy mapping will always be read-only in order to avoid the case where a user mode accidentally or maliciously writes into an application's WriteFile buffer. (Also note that when the WinFsp driver sets up this mapping, it does so in a way that ensures that there is no accidental data leakage from the application into the user mode file system either.)

答案2

得分: 0

由于buf[0] = 1 // (4)之后没有打印任何内容,我们无法确定panic是来自这行代码还是之后的某行代码;您需要进一步调试以找出错误所在。

实际上:您粘贴的堆栈跟踪提到了LiangFs/tool/memfs.go:310
如果这个行号指的是您链接的文件,那么这行是您的.Write()函数中的return指令。

错误可能是由两个defer调用触发的(当您从函数返回时执行)。

英文:

Since nothing is printed after buf[0] = 1 // (4), we don't know wether the panic comes from this line of code or a line afterwards ; you have to debug further to spot where the bug lies.

Actually : the stack trace you pasted mentions LiangFs/tool/memfs.go:310.
If this line number refers to the file you linked to, this line is the return instruction in your .Write() function.

The error must be triggered by one of the two defer calls (which get executed when you return from your function).

huangapple
  • 本文由 发表于 2021年9月26日 18:17:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/69333916.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定