os: fix regression with handling of nil *File

Use of a nil *File as an argument should not result in a panic,
but result in the ErrInvalid error being returned.
Fix the copy_file_range implementation to preserve this semantic.

Fixes #40115

Change-Id: Iad5ac39664a3efb7964cf55685be636940a8db13
Reviewed-on: https://go-review.googlesource.com/c/go/+/241417
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/src/os/readfrom_linux.go b/src/os/readfrom_linux.go
index ed275e1..63ea45c 100644
--- a/src/os/readfrom_linux.go
+++ b/src/os/readfrom_linux.go
@@ -32,6 +32,11 @@
 	if !ok {
 		return 0, false, nil
 	}
+	if src.checkValid("ReadFrom") != nil {
+		// Avoid returning the error as we report handled as false,
+		// leave further error handling as the responsibility of the caller.
+		return 0, false, nil
+	}
 
 	written, handled, err = pollCopyFileRange(&f.pfd, &src.pfd, remain)
 	if lr != nil {
diff --git a/src/os/readfrom_linux_test.go b/src/os/readfrom_linux_test.go
index b6f5cb7..00faf39 100644
--- a/src/os/readfrom_linux_test.go
+++ b/src/os/readfrom_linux_test.go
@@ -8,6 +8,7 @@
 	"bytes"
 	"internal/poll"
 	"io"
+	"io/ioutil"
 	"math/rand"
 	. "os"
 	"path/filepath"
@@ -170,6 +171,35 @@
 			mustContainData(t, dst, data)
 		})
 	})
+	t.Run("Nil", func(t *testing.T) {
+		var nilFile *File
+		anyFile, err := ioutil.TempFile("", "")
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer Remove(anyFile.Name())
+		defer anyFile.Close()
+
+		if _, err := io.Copy(nilFile, nilFile); err != ErrInvalid {
+			t.Errorf("io.Copy(nilFile, nilFile) = %v, want %v", err, ErrInvalid)
+		}
+		if _, err := io.Copy(anyFile, nilFile); err != ErrInvalid {
+			t.Errorf("io.Copy(anyFile, nilFile) = %v, want %v", err, ErrInvalid)
+		}
+		if _, err := io.Copy(nilFile, anyFile); err != ErrInvalid {
+			t.Errorf("io.Copy(nilFile, anyFile) = %v, want %v", err, ErrInvalid)
+		}
+
+		if _, err := nilFile.ReadFrom(nilFile); err != ErrInvalid {
+			t.Errorf("nilFile.ReadFrom(nilFile) = %v, want %v", err, ErrInvalid)
+		}
+		if _, err := anyFile.ReadFrom(nilFile); err != ErrInvalid {
+			t.Errorf("anyFile.ReadFrom(nilFile) = %v, want %v", err, ErrInvalid)
+		}
+		if _, err := nilFile.ReadFrom(anyFile); err != ErrInvalid {
+			t.Errorf("nilFile.ReadFrom(anyFile) = %v, want %v", err, ErrInvalid)
+		}
+	})
 }
 
 func testCopyFileRange(t *testing.T, size int64, limit int64) {