Skip to content

Commit eac8b12

Browse files
committed
🧇 mmap: fix size handling
- Fix nil close on empty files. - Handle size overflow. - Handle incomplete mappings on Windows. ref: https://github.com/golang/go/blob/master/src/cmd/go/internal/mmap/mmap_windows.go
1 parent aff7d0a commit eac8b12

File tree

2 files changed

+25
-7
lines changed

2 files changed

+25
-7
lines changed

mmap/mmap.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,31 @@ import (
77
"unsafe"
88
)
99

10+
var ErrFileTooLarge = errors.New("file too large")
11+
1012
// ReadFile maps the named file into memory for reading.
1113
// On success, it returns the mapped data as a byte slice or a string,
1214
// and a function that unmaps the data.
1315
func ReadFile[T ~[]byte | ~string](name string) (data T, close func() error, err error) {
1416
f, err := os.Open(name)
1517
if err != nil {
16-
return
18+
return data, nil, err
1719
}
1820
defer f.Close()
1921

2022
fs, err := f.Stat()
2123
if err != nil {
22-
return
24+
return data, nil, err
2325
}
2426

25-
size := fs.Size()
26-
if size == 0 {
27-
return
27+
size64 := fs.Size()
28+
if size64 == 0 {
29+
return data, func() error { return nil }, nil
30+
}
31+
32+
size := int(size64)
33+
if int64(size) != size64 {
34+
return data, nil, ErrFileTooLarge
2835
}
2936

3037
addr, close, err := readFile(f, uintptr(size))
@@ -39,7 +46,7 @@ func ReadFile[T ~[]byte | ~string](name string) (data T, close func() error, err
3946
return *(*T)(unsafe.Pointer(&b)), close, nil
4047
}
4148

42-
func readFileFallback[T ~[]byte | ~string](f *os.File, size int64) (data T, close func() error, err error) {
49+
func readFileFallback[T ~[]byte | ~string](f *os.File, size int) (data T, close func() error, err error) {
4350
b := make([]byte, size)
4451
if _, err = io.ReadFull(f, b); err != nil {
4552
return

mmap/mmap_windows.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"golang.org/x/sys/windows"
88
)
99

10-
func readFile(f *os.File, _ uintptr) (addr unsafe.Pointer, close func() error, err error) {
10+
func readFile(f *os.File, size uintptr) (addr unsafe.Pointer, close func() error, err error) {
1111
handle, err := windows.CreateFileMapping(windows.Handle(f.Fd()), nil, windows.PAGE_READONLY, 0, 0, nil)
1212
if err != nil {
1313
return nil, nil, os.NewSyscallError("CreateFileMappingW", err)
@@ -18,6 +18,17 @@ func readFile(f *os.File, _ uintptr) (addr unsafe.Pointer, close func() error, e
1818
if err != nil {
1919
return nil, nil, os.NewSyscallError("MapViewOfFile", err)
2020
}
21+
22+
var info windows.MemoryBasicInformation
23+
if err := windows.VirtualQuery(addrUintptr, &info, unsafe.Sizeof(info)); err != nil {
24+
_ = windows.UnmapViewOfFile(addrUintptr)
25+
return nil, nil, os.NewSyscallError("VirtualQuery", err)
26+
}
27+
if info.RegionSize < size {
28+
_ = windows.UnmapViewOfFile(addrUintptr)
29+
return nil, nil, ErrFileTooLarge
30+
}
31+
2132
return *(*unsafe.Pointer)(unsafe.Pointer(&addrUintptr)), // workaround for unsafeptr check in go vet, see https://github.com/golang/go/issues/58625
2233
func() error {
2334
return windows.UnmapViewOfFile(addrUintptr)

0 commit comments

Comments
 (0)