mmap: allow mapping a zero-sized file
Fixes golang/go#56261
Change-Id: Iff450c457edf2b83b24b35199a2643ef9fed48ab
Reviewed-on: https://go-review.googlesource.com/c/exp/+/443576
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Nigel Tao (INACTIVE; USE @golang.org INSTEAD) <nigeltao@google.com>
diff --git a/mmap/manual_test_program.go b/mmap/manual_test_program.go
index a1ab17b..5c212b6 100644
--- a/mmap/manual_test_program.go
+++ b/mmap/manual_test_program.go
@@ -24,6 +24,10 @@
var garbage []byte
func main() {
+ // If you replace "manual_test_program.go" with the name of an empty (zero
+ // sized) file (and set "const debug = true") then you will not necessarily
+ // see two "munmap log messages", since some operating systems will not
+ // allow a zero sized mapping so there is no need for a finalizer to unmap.
const filename = "manual_test_program.go"
for _, explicitClose := range []bool{false, true} {
@@ -31,6 +35,7 @@
if err != nil {
log.Fatalf("Open: %v", err)
}
+ println("Open succeeded; Len =", r.Len())
if explicitClose {
r.Close()
} else {
diff --git a/mmap/mmap_unix.go b/mmap/mmap_unix.go
index ae12499..5ceb69b 100644
--- a/mmap/mmap_unix.go
+++ b/mmap/mmap_unix.go
@@ -38,6 +38,9 @@
func (r *ReaderAt) Close() error {
if r.data == nil {
return nil
+ } else if len(r.data) == 0 {
+ r.data = nil
+ return nil
}
data := r.data
r.data = nil
@@ -91,7 +94,14 @@
size := fi.Size()
if size == 0 {
- return &ReaderAt{}, nil
+ // Treat (size == 0) as a special case, avoiding the syscall, since
+ // "man 2 mmap" says "the length... must be greater than 0".
+ //
+ // As we do not call syscall.Mmap, there is no need to call
+ // runtime.SetFinalizer to enforce a balancing syscall.Munmap.
+ return &ReaderAt{
+ data: make([]byte, 0),
+ }, nil
}
if size < 0 {
return nil, fmt.Errorf("mmap: file %q has negative size", filename)
diff --git a/mmap/mmap_windows.go b/mmap/mmap_windows.go
index d898828..ea1d1cb 100644
--- a/mmap/mmap_windows.go
+++ b/mmap/mmap_windows.go
@@ -36,6 +36,9 @@
func (r *ReaderAt) Close() error {
if r.data == nil {
return nil
+ } else if len(r.data) == 0 {
+ r.data = nil
+ return nil
}
data := r.data
r.data = nil
@@ -89,7 +92,14 @@
size := fi.Size()
if size == 0 {
- return &ReaderAt{}, nil
+ // Treat (size == 0) as a special case, avoiding the syscall, to be
+ // consistent with mmap_unix.go.
+ //
+ // As we do not call syscall.MapViewOfFile, there is no need to call
+ // runtime.SetFinalizer to enforce a balancing syscall.UnmapViewOfFile.
+ return &ReaderAt{
+ data: make([]byte, 0),
+ }, nil
}
if size < 0 {
return nil, fmt.Errorf("mmap: file %q has negative size", filename)