edsrzf / mmap-go

A portable mmap package for Go

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[signal SIGBUS: bus error code=0x2 addr=0x1e4001 pc=0x2535]

AllenRay opened this issue · comments

go version
1.7.1
os
macos sierra

when i use mmap-go to write bytes to file occur error. the stack as below

unexpected fault address 0x1e4001
fatal error: fault
[signal SIGBUS: bus error code=0x2 addr=0x1e4001 pc=0x2535]

goroutine 1 [running]:
runtime.throw(0xb37ee, 0x5)
/usr/local/go/src/runtime/panic.go:566 +0x95 fp=0xc420035da0 sp=0xc420035d80
runtime.sigpanic()
/usr/local/go/src/runtime/sigpanic_unix.go:21 +0x1d0 fp=0xc420035df8 sp=0xc420035da0
main.main()
/Users/leizhenyu/work/src/github.com/GoRocketMQ/start/main-1.go:58 +0x4f5 fp=0xc420035f48 sp=0xc420035df8
runtime.main()
/usr/local/go/src/runtime/proc.go:183 +0x1f4 fp=0xc420035fa0 sp=0xc420035f48
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:2086 +0x1 fp=0xc420035fa8 sp=0xc420035fa0
exit status 2

the line 58 code as below

mmaped[0] = 'x'

commented

me too :(

the same problem

A minimal reproduction case would be helpful here.

@edsrzf I hit the same problem on macos. This reproduced when provided mapped size is bigger than actual file size. So, in my case the code, called for a file f which size is 0:

mf, err := mmap.MapRegion(f, 12345*4096, mmap.RDWR, 0, 0)
...

doesn't change the file f size, so it remained 0. Seems like macos doesn't extend the file with the mapping. Can be easily fixed by f.Truncate(12345*4096) for the example above. Please consider.

I've also been investigating this, and made a repro for it. I can repro it on both fedora and ubuntu. However, IIUC, it's not actually an issue with mmap per se, rather a filesystem thing.

See https://gist.github.com/holiman/ce51945058d2befaf718de3804fb9352 .

What that gist does, is that it creates a file, in the os temp folder, of 10Gb. On my fedora, the temp partition only holds 1Gb. Yet, the file creation completes without any problems.

If I check the file, du will tell me it's a few K bytes, and ls will tell me it's 10Gb. See https://unix.stackexchange.com/a/436318 for more info:

ls -l will give you the apparent size of the file, which is the number of bytes a program would read if it read the file from start to finish. du would give you the size of the file "on disk".

So what we've got is a 'sparse' file. And even though it's possible to read 10Gb from it, the underlying disk resource is way smaller. And the problem is that if I later try to fill it with data, at some point the underlying disk resource will grow larger than what the disk can hold ( in my case 1Gb), and there will be an error.

Back to mmap: in our use of mmap-go, we create a large file, truncate to size, close, and then do an mmap on it -- erroneously believing that we can use the full size of the mmap data, as it's already backed by the filesystem. Later on, as we're just filling the bytes, the same thing will happen though, and unexpected fault address is surfaced.

I'm not sure how this can be avoided. One (boring) solution could be to actually fill the file with data, write junk to it before mmap, to ensure that the disk actually will be able to store the data.

For memory maps where the caller intends to write to the region, a check like this can be used to ensure that the required size is actually addressable:

	handle := int(dump.Fd())
	if err := syscall.Fallocate(handle, 0, 0, int64(fSize)); err != nil {
		return fmt.Errorf("Fallocate failed: %v", err)
	}

More info: https://unix.stackexchange.com/a/292849

It's obviously unix-specific.

It's obviously unix-specific.

It's linux specific¹. Other unix variants do not have fallocate. As with all use of package syscall, the Go source file importing it should have an appropriate go:build (or +build) build constraint. In this case //go:build linux and/or // +build linux with an alternative //go:build freebsd || netbsd || openbsd || dragonfly (etc) file that uses CGO to call C.posix_fallocate (unfortunately neither syscall nor golang.org/x/sys/unix provide a non-linux version of this functionality because it's in libc and not a syscall for other systems).

¹ The first paragraph of the fallocate(1) man page says:

This is a nonportable, Linux-specific system call. For the
portable, POSIX.1-specified method of ensuring that space is
allocated for a file, see posix_fallocate(3).