]> Cypherpunks repositories - gostls13.git/commitdiff
os: don't consult Is methods on non-syscall error types
authorDamien Neil <dneil@google.com>
Fri, 2 Aug 2019 18:18:56 +0000 (11:18 -0700)
committerDamien Neil <dneil@google.com>
Fri, 2 Aug 2019 21:09:50 +0000 (21:09 +0000)
CL #163058 moves interpretation of platform-specific errors to the
syscall package. Package syscall errors implement an Is method which
os.IsPermission etc. consult. This results in an unintended semantic
change to the os package predicate functions: The following program
now prints 'true' where it used to print 'false':

package main
import "os"
type myError struct{ error }
func (e myError) Is(target error) bool { return target == os.ErrPermission }
func main() { println(os.IsPermission(myError{})) }

Change the os package error predicate functions to only examine syscall
errors, avoiding this semantic change.

This CL does retain one minor semantic change: On Plan9, os.IsPermission
used to return true for any error with text containing the string
"permission denied". It now only returns true for a syscall.ErrorString
containing that text.

Change-Id: I6b512b1de6ced46c2f1cc8d264fa2495ae7bf9f5
Reviewed-on: https://go-review.googlesource.com/c/go/+/188817
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
src/os/error.go
src/os/error_errno.go [new file with mode: 0644]
src/os/error_plan9.go [new file with mode: 0644]
src/os/error_test.go

index 09ba158677158afe0b6f37f67e87bc799fdd8233..0e8e2d47f8fa380dbcddfa43564fcd3748c9ac4a 100644 (file)
@@ -115,7 +115,8 @@ func underlyingErrorIs(err, target error) bool {
        if err == target {
                return true
        }
-       e, ok := err.(interface{ Is(error) bool })
+       // To preserve prior behavior, only examine syscall errors.
+       e, ok := err.(syscallErrorType)
        return ok && e.Is(target)
 }
 
diff --git a/src/os/error_errno.go b/src/os/error_errno.go
new file mode 100644 (file)
index 0000000..31ae05a
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9
+
+package os
+
+import "syscall"
+
+type syscallErrorType = syscall.Errno
diff --git a/src/os/error_plan9.go b/src/os/error_plan9.go
new file mode 100644 (file)
index 0000000..af6065d
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+type syscallErrorType = syscall.ErrorString
index a03bd28b9ae908277bd88e50deb6e890fc6a8e6b..3d921578fd294fb3db45821687d921620591c624 100644 (file)
@@ -175,3 +175,13 @@ func TestPathErrorUnwrap(t *testing.T) {
                t.Error("errors.Is failed, wanted success")
        }
 }
+
+type myErrorIs struct{ error }
+
+func (e myErrorIs) Is(target error) bool { return target == e.error }
+
+func TestErrorIsMethods(t *testing.T) {
+       if os.IsPermission(myErrorIs{os.ErrPermission}) {
+               t.Error("os.IsPermission(err) = true when err.Is(os.ErrPermission), wanted false")
+       }
+}