summaryrefslogtreecommitdiffhomepage
path: root/pkg/errors
diff options
context:
space:
mode:
authorZach Koopmans <zkoopmans@google.com>2021-10-29 14:00:52 -0700
committergVisor bot <gvisor-bot@google.com>2021-10-29 14:03:16 -0700
commitb822923b706d6d2c5206451040f51a8c2f961353 (patch)
tree393f215aa879b909c9c9debd5e893bddb61ee50a /pkg/errors
parent1953d2ad28d405a3ab028feba7b6fca18339e9be (diff)
[syserr] Covert all linuxerr returns to error type.
Change the linuxerr.ErrorFromErrno to return an error type and not a *errors.Error type. The latter results in problems comparing to nil as <nil><nil> != <nil><*errors.Error>. In a follow up, there will be a change to remove *errors.Error.Errno(), which will also encourage users to not use Errnos to reference linuxerr. PiperOrigin-RevId: 406444419
Diffstat (limited to 'pkg/errors')
-rw-r--r--pkg/errors/linuxerr/BUILD1
-rw-r--r--pkg/errors/linuxerr/linuxerr.go123
-rw-r--r--pkg/errors/linuxerr/linuxerr_test.go22
3 files changed, 79 insertions, 67 deletions
diff --git a/pkg/errors/linuxerr/BUILD b/pkg/errors/linuxerr/BUILD
index e73b0e28a..5b59ebd6e 100644
--- a/pkg/errors/linuxerr/BUILD
+++ b/pkg/errors/linuxerr/BUILD
@@ -21,7 +21,6 @@ go_test(
srcs = ["linuxerr_test.go"],
deps = [
":linuxerr",
- "//pkg/abi/linux/errno",
"//pkg/errors",
"@org_golang_x_sys//unix:go_default_library",
],
diff --git a/pkg/errors/linuxerr/linuxerr.go b/pkg/errors/linuxerr/linuxerr.go
index 5905ef593..e44a55afd 100644
--- a/pkg/errors/linuxerr/linuxerr.go
+++ b/pkg/errors/linuxerr/linuxerr.go
@@ -34,41 +34,41 @@ const maxErrno uint32 = errno.EHWPOISON + 1
// (e.g. unix.Errno(EPERM.Errno()) == unix.EPERM is true). Converting unix/syscall.Errno
// to the errors should be done via the lookup methods provided.
var (
- NOERROR = errors.New(errno.NOERRNO, "not an error")
- EPERM = errors.New(errno.EPERM, "operation not permitted")
- ENOENT = errors.New(errno.ENOENT, "no such file or directory")
- ESRCH = errors.New(errno.ESRCH, "no such process")
- EINTR = errors.New(errno.EINTR, "interrupted system call")
- EIO = errors.New(errno.EIO, "I/O error")
- ENXIO = errors.New(errno.ENXIO, "no such device or address")
- E2BIG = errors.New(errno.E2BIG, "argument list too long")
- ENOEXEC = errors.New(errno.ENOEXEC, "exec format error")
- EBADF = errors.New(errno.EBADF, "bad file number")
- ECHILD = errors.New(errno.ECHILD, "no child processes")
- EAGAIN = errors.New(errno.EAGAIN, "try again")
- ENOMEM = errors.New(errno.ENOMEM, "out of memory")
- EACCES = errors.New(errno.EACCES, "permission denied")
- EFAULT = errors.New(errno.EFAULT, "bad address")
- ENOTBLK = errors.New(errno.ENOTBLK, "block device required")
- EBUSY = errors.New(errno.EBUSY, "device or resource busy")
- EEXIST = errors.New(errno.EEXIST, "file exists")
- EXDEV = errors.New(errno.EXDEV, "cross-device link")
- ENODEV = errors.New(errno.ENODEV, "no such device")
- ENOTDIR = errors.New(errno.ENOTDIR, "not a directory")
- EISDIR = errors.New(errno.EISDIR, "is a directory")
- EINVAL = errors.New(errno.EINVAL, "invalid argument")
- ENFILE = errors.New(errno.ENFILE, "file table overflow")
- EMFILE = errors.New(errno.EMFILE, "too many open files")
- ENOTTY = errors.New(errno.ENOTTY, "not a typewriter")
- ETXTBSY = errors.New(errno.ETXTBSY, "text file busy")
- EFBIG = errors.New(errno.EFBIG, "file too large")
- ENOSPC = errors.New(errno.ENOSPC, "no space left on device")
- ESPIPE = errors.New(errno.ESPIPE, "illegal seek")
- EROFS = errors.New(errno.EROFS, "read-only file system")
- EMLINK = errors.New(errno.EMLINK, "too many links")
- EPIPE = errors.New(errno.EPIPE, "broken pipe")
- EDOM = errors.New(errno.EDOM, "math argument out of domain of func")
- ERANGE = errors.New(errno.ERANGE, "math result not representable")
+ noError *errors.Error = nil
+ EPERM = errors.New(errno.EPERM, "operation not permitted")
+ ENOENT = errors.New(errno.ENOENT, "no such file or directory")
+ ESRCH = errors.New(errno.ESRCH, "no such process")
+ EINTR = errors.New(errno.EINTR, "interrupted system call")
+ EIO = errors.New(errno.EIO, "I/O error")
+ ENXIO = errors.New(errno.ENXIO, "no such device or address")
+ E2BIG = errors.New(errno.E2BIG, "argument list too long")
+ ENOEXEC = errors.New(errno.ENOEXEC, "exec format error")
+ EBADF = errors.New(errno.EBADF, "bad file number")
+ ECHILD = errors.New(errno.ECHILD, "no child processes")
+ EAGAIN = errors.New(errno.EAGAIN, "try again")
+ ENOMEM = errors.New(errno.ENOMEM, "out of memory")
+ EACCES = errors.New(errno.EACCES, "permission denied")
+ EFAULT = errors.New(errno.EFAULT, "bad address")
+ ENOTBLK = errors.New(errno.ENOTBLK, "block device required")
+ EBUSY = errors.New(errno.EBUSY, "device or resource busy")
+ EEXIST = errors.New(errno.EEXIST, "file exists")
+ EXDEV = errors.New(errno.EXDEV, "cross-device link")
+ ENODEV = errors.New(errno.ENODEV, "no such device")
+ ENOTDIR = errors.New(errno.ENOTDIR, "not a directory")
+ EISDIR = errors.New(errno.EISDIR, "is a directory")
+ EINVAL = errors.New(errno.EINVAL, "invalid argument")
+ ENFILE = errors.New(errno.ENFILE, "file table overflow")
+ EMFILE = errors.New(errno.EMFILE, "too many open files")
+ ENOTTY = errors.New(errno.ENOTTY, "not a typewriter")
+ ETXTBSY = errors.New(errno.ETXTBSY, "text file busy")
+ EFBIG = errors.New(errno.EFBIG, "file too large")
+ ENOSPC = errors.New(errno.ENOSPC, "no space left on device")
+ ESPIPE = errors.New(errno.ESPIPE, "illegal seek")
+ EROFS = errors.New(errno.EROFS, "read-only file system")
+ EMLINK = errors.New(errno.EMLINK, "too many links")
+ EPIPE = errors.New(errno.EPIPE, "broken pipe")
+ EDOM = errors.New(errno.EDOM, "math argument out of domain of func")
+ ERANGE = errors.New(errno.ERANGE, "math result not representable")
// Errno values from include/uapi/asm-generic/errno.h.
EDEADLK = errors.New(errno.EDEADLK, "resource deadlock would occur")
@@ -186,7 +186,7 @@ var errNotValidError = errors.New(errno.Errno(maxErrno), "not a valid error")
// errnos (especially uint32(sycall.Errno)) and *errors.Error.
var errorSlice = []*errors.Error{
// Errno values from include/uapi/asm-generic/errno-base.h.
- errno.NOERRNO: NOERROR,
+ errno.NOERRNO: noError,
errno.EPERM: EPERM,
errno.ENOENT: ENOENT,
errno.ESRCH: ESRCH,
@@ -324,32 +324,45 @@ var errorSlice = []*errors.Error{
errno.EHWPOISON: EHWPOISON,
}
-// ErrorFromErrno gets an error from the list and panics if an invalid entry is requested.
-func ErrorFromErrno(e errno.Errno) *errors.Error {
- err := errorSlice[e]
+// ErrorFromUnix returns a linuxerr from a unix.Errno.
+func ErrorFromUnix(err unix.Errno) error {
+ if err == unix.Errno(0) {
+ return nil
+ }
+ e := errorSlice[errno.Errno(err)]
// Done this way because a single comparison in benchmarks is 2-3 faster
// than something like ( if err == nil && err > 0 ).
- if err != errNotValidError {
- return err
+ if e == errNotValidError {
+ panic(fmt.Sprintf("invalid error requested with errno: %v", e))
}
- panic(fmt.Sprintf("invalid error requested with errno: %d", e))
+ return e
}
-// Equals compars a linuxerr to a given error
-// TODO(b/34162363): Remove when syserror is removed.
-func Equals(e *errors.Error, err error) bool {
- if err == nil {
- return e == NOERROR || e == nil
+// ToError converts a linuxerr to an error type.
+func ToError(err *errors.Error) error {
+ if err == noError {
+ return nil
}
- if e == nil {
- return err == NOERROR || err == unix.Errno(0)
+ return err
+}
+
+// ToUnix converts a linuxerr to a unix.Errno.
+func ToUnix(e *errors.Error) unix.Errno {
+ var unixErr unix.Errno
+ if e != noError {
+ unixErr = unix.Errno(e.Errno())
}
+ return unixErr
+}
- switch err.(type) {
- case *errors.Error:
- return e == err
- case unix.Errno, error:
- return unix.Errno(e.Errno()) == err
+// Equals compars a linuxerr to a given error.
+func Equals(e *errors.Error, err error) bool {
+ var unixErr unix.Errno
+ if e != noError {
+ unixErr = unix.Errno(e.Errno())
+ }
+ if err == nil {
+ err = noError
}
- return false
+ return e == err || unixErr == err
}
diff --git a/pkg/errors/linuxerr/linuxerr_test.go b/pkg/errors/linuxerr/linuxerr_test.go
index df7cd1c5a..b99884b22 100644
--- a/pkg/errors/linuxerr/linuxerr_test.go
+++ b/pkg/errors/linuxerr/linuxerr_test.go
@@ -23,7 +23,6 @@ import (
"testing"
"golang.org/x/sys/unix"
- "gvisor.dev/gvisor/pkg/abi/linux/errno"
gErrors "gvisor.dev/gvisor/pkg/errors"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
)
@@ -121,7 +120,7 @@ func BenchmarkReturnLinuxerr(b *testing.B) {
func BenchmarkConvertUnixLinuxerr(b *testing.B) {
var localError error
for i := b.N; i > 0; i-- {
- localError = linuxerr.ErrorFromErrno(errno.Errno(unix.EINVAL))
+ localError = linuxerr.ErrorFromUnix(unix.EINVAL)
}
if localError != nil {
return
@@ -131,7 +130,7 @@ func BenchmarkConvertUnixLinuxerr(b *testing.B) {
func BenchmarkConvertUnixLinuxerrZero(b *testing.B) {
var localError error
for i := b.N; i > 0; i-- {
- localError = linuxerr.ErrorFromErrno(errno.Errno(0))
+ localError = linuxerr.ErrorFromUnix(unix.Errno(0))
}
if localError != nil {
return
@@ -179,7 +178,7 @@ func TestErrorTranslation(t *testing.T) {
func TestSyscallErrnoToErrors(t *testing.T) {
for _, tc := range []struct {
errno syscall.Errno
- err *gErrors.Error
+ err error
}{
{errno: syscall.EACCES, err: linuxerr.EACCES},
{errno: syscall.EAGAIN, err: linuxerr.EAGAIN},
@@ -200,9 +199,9 @@ func TestSyscallErrnoToErrors(t *testing.T) {
{errno: syscall.EWOULDBLOCK, err: linuxerr.EAGAIN},
} {
t.Run(tc.errno.Error(), func(t *testing.T) {
- e := linuxerr.ErrorFromErrno(errno.Errno(tc.errno))
+ e := linuxerr.ErrorFromUnix(unix.Errno(tc.errno))
if e != tc.err {
- t.Fatalf("Mismatch errors: want: %+v (%d) got: %+v %d", tc.err, tc.err.Errno(), e, e.Errno())
+ t.Fatalf("Mismatch errors: want: %+v %T got: %+v %T", tc.err, tc.err, e, e)
}
})
}
@@ -212,6 +211,7 @@ func TestSyscallErrnoToErrors(t *testing.T) {
// unix.Errno and linuxerr.
// TODO (b/34162363): Remove this.
func TestEqualsMethod(t *testing.T) {
+ noError := linuxerr.ErrorFromUnix(unix.Errno(0))
for _, tc := range []struct {
name string
linuxErr []*gErrors.Error
@@ -220,20 +220,20 @@ func TestEqualsMethod(t *testing.T) {
}{
{
name: "compare nil",
- linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR},
- err: []error{nil, linuxerr.NOERROR, unix.Errno(0)},
+ linuxErr: []*gErrors.Error{nil},
+ err: []error{nil, noError, unix.Errno(0)},
equal: true,
},
{
name: "linuxerr nil error not",
- linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR},
+ linuxErr: []*gErrors.Error{nil},
err: []error{unix.Errno(1), linuxerr.EPERM, linuxerr.EACCES},
equal: false,
},
{
name: "linuxerr not nil error nil",
linuxErr: []*gErrors.Error{linuxerr.ENOENT},
- err: []error{nil, unix.Errno(0), linuxerr.NOERROR},
+ err: []error{nil, unix.Errno(0)},
equal: false,
},
{
@@ -250,7 +250,7 @@ func TestEqualsMethod(t *testing.T) {
},
{
name: "other error",
- linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR, linuxerr.E2BIG, linuxerr.EINVAL},
+ linuxErr: []*gErrors.Error{nil, linuxerr.E2BIG, linuxerr.EINVAL},
err: []error{fs.ErrInvalid, io.EOF},
equal: false,
},