diff options
author | Damien Neil <dneil@google.com> | 2019-08-02 11:18:56 -0700 |
---|---|---|
committer | Damien Neil <dneil@google.com> | 2019-08-02 21:09:50 +0000 |
commit | d178c5888f06918e8dbd221f26c707e501a9fa98 (patch) | |
tree | faca9c7b6f04f490a882f0027b3958cc83a5bc78 | |
parent | 55e23cb1fe18c6784b573a44bce4c798a1983c2f (diff) | |
download | go-d178c5888f06918e8dbd221f26c707e501a9fa98.tar.gz go-d178c5888f06918e8dbd221f26c707e501a9fa98.zip |
os: don't consult Is methods on non-syscall error types
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>
-rw-r--r-- | src/os/error.go | 3 | ||||
-rw-r--r-- | src/os/error_errno.go | 11 | ||||
-rw-r--r-- | src/os/error_plan9.go | 9 | ||||
-rw-r--r-- | src/os/error_test.go | 10 |
4 files changed, 32 insertions, 1 deletions
diff --git a/src/os/error.go b/src/os/error.go index 09ba158677..0e8e2d47f8 100644 --- a/src/os/error.go +++ b/src/os/error.go @@ -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 index 0000000000..31ae05a21e --- /dev/null +++ b/src/os/error_errno.go @@ -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 index 0000000000..af6065db56 --- /dev/null +++ b/src/os/error_plan9.go @@ -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 diff --git a/src/os/error_test.go b/src/os/error_test.go index a03bd28b9a..3d921578fd 100644 --- a/src/os/error_test.go +++ b/src/os/error_test.go @@ -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") + } +} |