diff options
author | Zach Koopmans <zkoopmans@google.com> | 2021-10-29 14:00:52 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-10-29 14:03:16 -0700 |
commit | b822923b706d6d2c5206451040f51a8c2f961353 (patch) | |
tree | 393f215aa879b909c9c9debd5e893bddb61ee50a | |
parent | 1953d2ad28d405a3ab028feba7b6fca18339e9be (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
-rw-r--r-- | pkg/errors/linuxerr/BUILD | 1 | ||||
-rw-r--r-- | pkg/errors/linuxerr/linuxerr.go | 123 | ||||
-rw-r--r-- | pkg/errors/linuxerr/linuxerr_test.go | 22 | ||||
-rw-r--r-- | pkg/p9/BUILD | 1 | ||||
-rw-r--r-- | pkg/p9/handlers.go | 11 | ||||
-rw-r--r-- | pkg/p9/server.go | 4 | ||||
-rw-r--r-- | pkg/sentry/kernel/task_syscall.go | 4 |
7 files changed, 88 insertions, 78 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, }, diff --git a/pkg/p9/BUILD b/pkg/p9/BUILD index 2b22b2203..2a307df38 100644 --- a/pkg/p9/BUILD +++ b/pkg/p9/BUILD @@ -22,7 +22,6 @@ go_library( "version.go", ], deps = [ - "//pkg/abi/linux/errno", "//pkg/errors", "//pkg/errors/linuxerr", "//pkg/fd", diff --git a/pkg/p9/handlers.go b/pkg/p9/handlers.go index a8f8a9d03..2657081e3 100644 --- a/pkg/p9/handlers.go +++ b/pkg/p9/handlers.go @@ -23,7 +23,6 @@ import ( "sync/atomic" "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/abi/linux/errno" "gvisor.dev/gvisor/pkg/errors" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/fd" @@ -46,7 +45,7 @@ func ExtractErrno(err error) unix.Errno { // Attempt to unwrap. switch e := err.(type) { case *errors.Error: - return unix.Errno(e.Errno()) + return linuxerr.ToUnix(e) case unix.Errno: return e case *os.PathError: @@ -69,7 +68,7 @@ func newErr(err error) *Rlerror { // ExtractLinuxerrErrno extracts a *errors.Error from a error, best effort. // TODO(b/34162363): Merge this with ExtractErrno. -func ExtractLinuxerrErrno(err error) *errors.Error { +func ExtractLinuxerrErrno(err error) error { switch err { case os.ErrNotExist: return linuxerr.ENOENT @@ -84,9 +83,9 @@ func ExtractLinuxerrErrno(err error) *errors.Error { // Attempt to unwrap. switch e := err.(type) { case *errors.Error: - return e + return linuxerr.ToError(e) case unix.Errno: - return linuxerr.ErrorFromErrno(errno.Errno(e)) + return linuxerr.ErrorFromUnix(e) case *os.PathError: return ExtractLinuxerrErrno(e.Err) case *os.SyscallError: @@ -103,7 +102,7 @@ func ExtractLinuxerrErrno(err error) *errors.Error { // newErrFromLinuxerr returns an Rlerror from the linuxerr list. // TODO(b/34162363): Merge this with newErr. func newErrFromLinuxerr(err error) *Rlerror { - return &Rlerror{Error: uint32(ExtractLinuxerrErrno(err).Errno())} + return &Rlerror{Error: uint32(ExtractErrno(err))} } // handler is implemented for server-handled messages. diff --git a/pkg/p9/server.go b/pkg/p9/server.go index 241ab44ef..6428ad745 100644 --- a/pkg/p9/server.go +++ b/pkg/p9/server.go @@ -19,7 +19,7 @@ import ( "runtime/debug" "sync/atomic" - "gvisor.dev/gvisor/pkg/abi/linux/errno" + "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/fd" "gvisor.dev/gvisor/pkg/fdchannel" @@ -510,7 +510,7 @@ func (cs *connState) handle(m message) (r message) { // It will be removed a followup, when all the unix.Errno errors are // replaced with linuxerr. if rlError, ok := r.(*Rlerror); ok { - e := linuxerr.ErrorFromErrno(errno.Errno(rlError.Error)) + e := linuxerr.ErrorFromUnix(unix.Errno(rlError.Error)) r = newErrFromLinuxerr(e) } } else { diff --git a/pkg/sentry/kernel/task_syscall.go b/pkg/sentry/kernel/task_syscall.go index 2b1d7e114..2b85fe1ca 100644 --- a/pkg/sentry/kernel/task_syscall.go +++ b/pkg/sentry/kernel/task_syscall.go @@ -381,7 +381,7 @@ func ExtractErrno(err error, sysno int) int { case unix.Errno: return int(err) case *errors.Error: - return int(err.Errno()) + return int(linuxerr.ToUnix(err)) case *memmap.BusError: // Bus errors may generate SIGBUS, but for syscalls they still // return EFAULT. See case in task_run.go where the fault is @@ -395,7 +395,7 @@ func ExtractErrno(err error, sysno int) int { return ExtractErrno(err.Err, sysno) default: if errno, ok := linuxerr.TranslateError(err); ok { - return int(errno.Errno()) + return int(linuxerr.ToUnix(errno)) } } panic(fmt.Sprintf("Unknown syscall %d error: %v", sysno, err)) |