Skip to content

Commit b822923

Browse files
zkoopmansgvisor-bot
authored andcommitted
[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
1 parent 1953d2a commit b822923

File tree

7 files changed

+88
-78
lines changed

7 files changed

+88
-78
lines changed

pkg/errors/linuxerr/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ go_test(
2121
srcs = ["linuxerr_test.go"],
2222
deps = [
2323
":linuxerr",
24-
"//pkg/abi/linux/errno",
2524
"//pkg/errors",
2625
"@org_golang_x_sys//unix:go_default_library",
2726
],

pkg/errors/linuxerr/linuxerr.go

Lines changed: 68 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -34,41 +34,41 @@ const maxErrno uint32 = errno.EHWPOISON + 1
3434
// (e.g. unix.Errno(EPERM.Errno()) == unix.EPERM is true). Converting unix/syscall.Errno
3535
// to the errors should be done via the lookup methods provided.
3636
var (
37-
NOERROR = errors.New(errno.NOERRNO, "not an error")
38-
EPERM = errors.New(errno.EPERM, "operation not permitted")
39-
ENOENT = errors.New(errno.ENOENT, "no such file or directory")
40-
ESRCH = errors.New(errno.ESRCH, "no such process")
41-
EINTR = errors.New(errno.EINTR, "interrupted system call")
42-
EIO = errors.New(errno.EIO, "I/O error")
43-
ENXIO = errors.New(errno.ENXIO, "no such device or address")
44-
E2BIG = errors.New(errno.E2BIG, "argument list too long")
45-
ENOEXEC = errors.New(errno.ENOEXEC, "exec format error")
46-
EBADF = errors.New(errno.EBADF, "bad file number")
47-
ECHILD = errors.New(errno.ECHILD, "no child processes")
48-
EAGAIN = errors.New(errno.EAGAIN, "try again")
49-
ENOMEM = errors.New(errno.ENOMEM, "out of memory")
50-
EACCES = errors.New(errno.EACCES, "permission denied")
51-
EFAULT = errors.New(errno.EFAULT, "bad address")
52-
ENOTBLK = errors.New(errno.ENOTBLK, "block device required")
53-
EBUSY = errors.New(errno.EBUSY, "device or resource busy")
54-
EEXIST = errors.New(errno.EEXIST, "file exists")
55-
EXDEV = errors.New(errno.EXDEV, "cross-device link")
56-
ENODEV = errors.New(errno.ENODEV, "no such device")
57-
ENOTDIR = errors.New(errno.ENOTDIR, "not a directory")
58-
EISDIR = errors.New(errno.EISDIR, "is a directory")
59-
EINVAL = errors.New(errno.EINVAL, "invalid argument")
60-
ENFILE = errors.New(errno.ENFILE, "file table overflow")
61-
EMFILE = errors.New(errno.EMFILE, "too many open files")
62-
ENOTTY = errors.New(errno.ENOTTY, "not a typewriter")
63-
ETXTBSY = errors.New(errno.ETXTBSY, "text file busy")
64-
EFBIG = errors.New(errno.EFBIG, "file too large")
65-
ENOSPC = errors.New(errno.ENOSPC, "no space left on device")
66-
ESPIPE = errors.New(errno.ESPIPE, "illegal seek")
67-
EROFS = errors.New(errno.EROFS, "read-only file system")
68-
EMLINK = errors.New(errno.EMLINK, "too many links")
69-
EPIPE = errors.New(errno.EPIPE, "broken pipe")
70-
EDOM = errors.New(errno.EDOM, "math argument out of domain of func")
71-
ERANGE = errors.New(errno.ERANGE, "math result not representable")
37+
noError *errors.Error = nil
38+
EPERM = errors.New(errno.EPERM, "operation not permitted")
39+
ENOENT = errors.New(errno.ENOENT, "no such file or directory")
40+
ESRCH = errors.New(errno.ESRCH, "no such process")
41+
EINTR = errors.New(errno.EINTR, "interrupted system call")
42+
EIO = errors.New(errno.EIO, "I/O error")
43+
ENXIO = errors.New(errno.ENXIO, "no such device or address")
44+
E2BIG = errors.New(errno.E2BIG, "argument list too long")
45+
ENOEXEC = errors.New(errno.ENOEXEC, "exec format error")
46+
EBADF = errors.New(errno.EBADF, "bad file number")
47+
ECHILD = errors.New(errno.ECHILD, "no child processes")
48+
EAGAIN = errors.New(errno.EAGAIN, "try again")
49+
ENOMEM = errors.New(errno.ENOMEM, "out of memory")
50+
EACCES = errors.New(errno.EACCES, "permission denied")
51+
EFAULT = errors.New(errno.EFAULT, "bad address")
52+
ENOTBLK = errors.New(errno.ENOTBLK, "block device required")
53+
EBUSY = errors.New(errno.EBUSY, "device or resource busy")
54+
EEXIST = errors.New(errno.EEXIST, "file exists")
55+
EXDEV = errors.New(errno.EXDEV, "cross-device link")
56+
ENODEV = errors.New(errno.ENODEV, "no such device")
57+
ENOTDIR = errors.New(errno.ENOTDIR, "not a directory")
58+
EISDIR = errors.New(errno.EISDIR, "is a directory")
59+
EINVAL = errors.New(errno.EINVAL, "invalid argument")
60+
ENFILE = errors.New(errno.ENFILE, "file table overflow")
61+
EMFILE = errors.New(errno.EMFILE, "too many open files")
62+
ENOTTY = errors.New(errno.ENOTTY, "not a typewriter")
63+
ETXTBSY = errors.New(errno.ETXTBSY, "text file busy")
64+
EFBIG = errors.New(errno.EFBIG, "file too large")
65+
ENOSPC = errors.New(errno.ENOSPC, "no space left on device")
66+
ESPIPE = errors.New(errno.ESPIPE, "illegal seek")
67+
EROFS = errors.New(errno.EROFS, "read-only file system")
68+
EMLINK = errors.New(errno.EMLINK, "too many links")
69+
EPIPE = errors.New(errno.EPIPE, "broken pipe")
70+
EDOM = errors.New(errno.EDOM, "math argument out of domain of func")
71+
ERANGE = errors.New(errno.ERANGE, "math result not representable")
7272

7373
// Errno values from include/uapi/asm-generic/errno.h.
7474
EDEADLK = errors.New(errno.EDEADLK, "resource deadlock would occur")
@@ -186,7 +186,7 @@ var errNotValidError = errors.New(errno.Errno(maxErrno), "not a valid error")
186186
// errnos (especially uint32(sycall.Errno)) and *errors.Error.
187187
var errorSlice = []*errors.Error{
188188
// Errno values from include/uapi/asm-generic/errno-base.h.
189-
errno.NOERRNO: NOERROR,
189+
errno.NOERRNO: noError,
190190
errno.EPERM: EPERM,
191191
errno.ENOENT: ENOENT,
192192
errno.ESRCH: ESRCH,
@@ -324,32 +324,45 @@ var errorSlice = []*errors.Error{
324324
errno.EHWPOISON: EHWPOISON,
325325
}
326326

327-
// ErrorFromErrno gets an error from the list and panics if an invalid entry is requested.
328-
func ErrorFromErrno(e errno.Errno) *errors.Error {
329-
err := errorSlice[e]
327+
// ErrorFromUnix returns a linuxerr from a unix.Errno.
328+
func ErrorFromUnix(err unix.Errno) error {
329+
if err == unix.Errno(0) {
330+
return nil
331+
}
332+
e := errorSlice[errno.Errno(err)]
330333
// Done this way because a single comparison in benchmarks is 2-3 faster
331334
// than something like ( if err == nil && err > 0 ).
332-
if err != errNotValidError {
333-
return err
335+
if e == errNotValidError {
336+
panic(fmt.Sprintf("invalid error requested with errno: %v", e))
334337
}
335-
panic(fmt.Sprintf("invalid error requested with errno: %d", e))
338+
return e
336339
}
337340

338-
// Equals compars a linuxerr to a given error
339-
// TODO(b/34162363): Remove when syserror is removed.
340-
func Equals(e *errors.Error, err error) bool {
341-
if err == nil {
342-
return e == NOERROR || e == nil
341+
// ToError converts a linuxerr to an error type.
342+
func ToError(err *errors.Error) error {
343+
if err == noError {
344+
return nil
343345
}
344-
if e == nil {
345-
return err == NOERROR || err == unix.Errno(0)
346+
return err
347+
}
348+
349+
// ToUnix converts a linuxerr to a unix.Errno.
350+
func ToUnix(e *errors.Error) unix.Errno {
351+
var unixErr unix.Errno
352+
if e != noError {
353+
unixErr = unix.Errno(e.Errno())
346354
}
355+
return unixErr
356+
}
347357

348-
switch err.(type) {
349-
case *errors.Error:
350-
return e == err
351-
case unix.Errno, error:
352-
return unix.Errno(e.Errno()) == err
358+
// Equals compars a linuxerr to a given error.
359+
func Equals(e *errors.Error, err error) bool {
360+
var unixErr unix.Errno
361+
if e != noError {
362+
unixErr = unix.Errno(e.Errno())
363+
}
364+
if err == nil {
365+
err = noError
353366
}
354-
return false
367+
return e == err || unixErr == err
355368
}

pkg/errors/linuxerr/linuxerr_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"testing"
2424

2525
"golang.org/x/sys/unix"
26-
"gvisor.dev/gvisor/pkg/abi/linux/errno"
2726
gErrors "gvisor.dev/gvisor/pkg/errors"
2827
"gvisor.dev/gvisor/pkg/errors/linuxerr"
2928
)
@@ -121,7 +120,7 @@ func BenchmarkReturnLinuxerr(b *testing.B) {
121120
func BenchmarkConvertUnixLinuxerr(b *testing.B) {
122121
var localError error
123122
for i := b.N; i > 0; i-- {
124-
localError = linuxerr.ErrorFromErrno(errno.Errno(unix.EINVAL))
123+
localError = linuxerr.ErrorFromUnix(unix.EINVAL)
125124
}
126125
if localError != nil {
127126
return
@@ -131,7 +130,7 @@ func BenchmarkConvertUnixLinuxerr(b *testing.B) {
131130
func BenchmarkConvertUnixLinuxerrZero(b *testing.B) {
132131
var localError error
133132
for i := b.N; i > 0; i-- {
134-
localError = linuxerr.ErrorFromErrno(errno.Errno(0))
133+
localError = linuxerr.ErrorFromUnix(unix.Errno(0))
135134
}
136135
if localError != nil {
137136
return
@@ -179,7 +178,7 @@ func TestErrorTranslation(t *testing.T) {
179178
func TestSyscallErrnoToErrors(t *testing.T) {
180179
for _, tc := range []struct {
181180
errno syscall.Errno
182-
err *gErrors.Error
181+
err error
183182
}{
184183
{errno: syscall.EACCES, err: linuxerr.EACCES},
185184
{errno: syscall.EAGAIN, err: linuxerr.EAGAIN},
@@ -200,9 +199,9 @@ func TestSyscallErrnoToErrors(t *testing.T) {
200199
{errno: syscall.EWOULDBLOCK, err: linuxerr.EAGAIN},
201200
} {
202201
t.Run(tc.errno.Error(), func(t *testing.T) {
203-
e := linuxerr.ErrorFromErrno(errno.Errno(tc.errno))
202+
e := linuxerr.ErrorFromUnix(unix.Errno(tc.errno))
204203
if e != tc.err {
205-
t.Fatalf("Mismatch errors: want: %+v (%d) got: %+v %d", tc.err, tc.err.Errno(), e, e.Errno())
204+
t.Fatalf("Mismatch errors: want: %+v %T got: %+v %T", tc.err, tc.err, e, e)
206205
}
207206
})
208207
}
@@ -212,6 +211,7 @@ func TestSyscallErrnoToErrors(t *testing.T) {
212211
// unix.Errno and linuxerr.
213212
// TODO (b/34162363): Remove this.
214213
func TestEqualsMethod(t *testing.T) {
214+
noError := linuxerr.ErrorFromUnix(unix.Errno(0))
215215
for _, tc := range []struct {
216216
name string
217217
linuxErr []*gErrors.Error
@@ -220,20 +220,20 @@ func TestEqualsMethod(t *testing.T) {
220220
}{
221221
{
222222
name: "compare nil",
223-
linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR},
224-
err: []error{nil, linuxerr.NOERROR, unix.Errno(0)},
223+
linuxErr: []*gErrors.Error{nil},
224+
err: []error{nil, noError, unix.Errno(0)},
225225
equal: true,
226226
},
227227
{
228228
name: "linuxerr nil error not",
229-
linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR},
229+
linuxErr: []*gErrors.Error{nil},
230230
err: []error{unix.Errno(1), linuxerr.EPERM, linuxerr.EACCES},
231231
equal: false,
232232
},
233233
{
234234
name: "linuxerr not nil error nil",
235235
linuxErr: []*gErrors.Error{linuxerr.ENOENT},
236-
err: []error{nil, unix.Errno(0), linuxerr.NOERROR},
236+
err: []error{nil, unix.Errno(0)},
237237
equal: false,
238238
},
239239
{
@@ -250,7 +250,7 @@ func TestEqualsMethod(t *testing.T) {
250250
},
251251
{
252252
name: "other error",
253-
linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR, linuxerr.E2BIG, linuxerr.EINVAL},
253+
linuxErr: []*gErrors.Error{nil, linuxerr.E2BIG, linuxerr.EINVAL},
254254
err: []error{fs.ErrInvalid, io.EOF},
255255
equal: false,
256256
},

pkg/p9/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ go_library(
2222
"version.go",
2323
],
2424
deps = [
25-
"//pkg/abi/linux/errno",
2625
"//pkg/errors",
2726
"//pkg/errors/linuxerr",
2827
"//pkg/fd",

pkg/p9/handlers.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"sync/atomic"
2424

2525
"golang.org/x/sys/unix"
26-
"gvisor.dev/gvisor/pkg/abi/linux/errno"
2726
"gvisor.dev/gvisor/pkg/errors"
2827
"gvisor.dev/gvisor/pkg/errors/linuxerr"
2928
"gvisor.dev/gvisor/pkg/fd"
@@ -46,7 +45,7 @@ func ExtractErrno(err error) unix.Errno {
4645
// Attempt to unwrap.
4746
switch e := err.(type) {
4847
case *errors.Error:
49-
return unix.Errno(e.Errno())
48+
return linuxerr.ToUnix(e)
5049
case unix.Errno:
5150
return e
5251
case *os.PathError:
@@ -69,7 +68,7 @@ func newErr(err error) *Rlerror {
6968

7069
// ExtractLinuxerrErrno extracts a *errors.Error from a error, best effort.
7170
// TODO(b/34162363): Merge this with ExtractErrno.
72-
func ExtractLinuxerrErrno(err error) *errors.Error {
71+
func ExtractLinuxerrErrno(err error) error {
7372
switch err {
7473
case os.ErrNotExist:
7574
return linuxerr.ENOENT
@@ -84,9 +83,9 @@ func ExtractLinuxerrErrno(err error) *errors.Error {
8483
// Attempt to unwrap.
8584
switch e := err.(type) {
8685
case *errors.Error:
87-
return e
86+
return linuxerr.ToError(e)
8887
case unix.Errno:
89-
return linuxerr.ErrorFromErrno(errno.Errno(e))
88+
return linuxerr.ErrorFromUnix(e)
9089
case *os.PathError:
9190
return ExtractLinuxerrErrno(e.Err)
9291
case *os.SyscallError:
@@ -103,7 +102,7 @@ func ExtractLinuxerrErrno(err error) *errors.Error {
103102
// newErrFromLinuxerr returns an Rlerror from the linuxerr list.
104103
// TODO(b/34162363): Merge this with newErr.
105104
func newErrFromLinuxerr(err error) *Rlerror {
106-
return &Rlerror{Error: uint32(ExtractLinuxerrErrno(err).Errno())}
105+
return &Rlerror{Error: uint32(ExtractErrno(err))}
107106
}
108107

109108
// handler is implemented for server-handled messages.

pkg/p9/server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
"runtime/debug"
2020
"sync/atomic"
2121

22-
"gvisor.dev/gvisor/pkg/abi/linux/errno"
22+
"golang.org/x/sys/unix"
2323
"gvisor.dev/gvisor/pkg/errors/linuxerr"
2424
"gvisor.dev/gvisor/pkg/fd"
2525
"gvisor.dev/gvisor/pkg/fdchannel"
@@ -510,7 +510,7 @@ func (cs *connState) handle(m message) (r message) {
510510
// It will be removed a followup, when all the unix.Errno errors are
511511
// replaced with linuxerr.
512512
if rlError, ok := r.(*Rlerror); ok {
513-
e := linuxerr.ErrorFromErrno(errno.Errno(rlError.Error))
513+
e := linuxerr.ErrorFromUnix(unix.Errno(rlError.Error))
514514
r = newErrFromLinuxerr(e)
515515
}
516516
} else {

pkg/sentry/kernel/task_syscall.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ func ExtractErrno(err error, sysno int) int {
381381
case unix.Errno:
382382
return int(err)
383383
case *errors.Error:
384-
return int(err.Errno())
384+
return int(linuxerr.ToUnix(err))
385385
case *memmap.BusError:
386386
// Bus errors may generate SIGBUS, but for syscalls they still
387387
// return EFAULT. See case in task_run.go where the fault is
@@ -395,7 +395,7 @@ func ExtractErrno(err error, sysno int) int {
395395
return ExtractErrno(err.Err, sysno)
396396
default:
397397
if errno, ok := linuxerr.TranslateError(err); ok {
398-
return int(errno.Errno())
398+
return int(linuxerr.ToUnix(errno))
399399
}
400400
}
401401
panic(fmt.Sprintf("Unknown syscall %d error: %v", sysno, err))

0 commit comments

Comments
 (0)