Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve error wrapping #336

Merged
merged 3 commits into from
Jul 2, 2021
Merged

improve error wrapping #336

merged 3 commits into from
Jul 2, 2021

Conversation

lmb
Copy link
Collaborator

@lmb lmb commented Jul 1, 2021

The library is inconsistent in how it wraps errors from syscalls. Sometimes it obscures the underlying error, sometimes it wraps it, sometimes it replaces it with a more specific error. This PR introduces a new approach:

  • We always wrap errors returned by SYS_BPF. This means that err == unix.EFOO will never work.
  • We always include the original errno when introducing a more specific error. This means that errors.Is(err, unix.EFOO) will always work.

This approach gives users access to syscall.Errno without painting us into a corner.

lmb added 3 commits July 1, 2021 16:52
Make sure we never return a plain syscall.Errno so that comparisons
using plain == never succeed. We do this to ensure that we can
influence error comparisons via errors.Is later on.
Get rid of wrapObjErr. This works by aliasing ErrNotExist to os.ErrNotExist,
since errors.Is(unix.ENOENT, os.ErrNotExist) is true.
We replace some errnos from map syscalls with more descriptive
sentinel errors. Include the original errno with the error so
that both

    errors.Is(err, ErrKeyNotExist)
    errors.Is(err, unix.ENOENT)

work. We'll use this for other errors in the future where we
want to introduce our own errors without breaking callers that
rely on the (coarser) errno semantics.
@lmb
Copy link
Collaborator Author

lmb commented Jul 1, 2021

@cyphar please take a look, I think this should solve your problem.

Copy link
Contributor

@cyphar cyphar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems very reasonable to me, and means that even the Err*-wrapped errors can be compared against either the syscall value or their Err* equivalent. Thanks for this!

@cyphar
Copy link
Contributor

cyphar commented Jul 2, 2021

Is it possible to get a new release with this patch? (In the meantime, I'll update the runc PR to use HEAD.)

Also, with regards to API stability -- with the last PR I sent you mentioned you don't want to make strong guarantees about errors. Is there any stability guarantee with errors.Is(..., unix.*) comparisons continuing to work with future versions?

Comment on lines +235 to +237
func SyscallError(err error, errno syscall.Errno) error {
return &syscallError{err, errno}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not export the type and use it directly? This is what golang stdlib does with types such as os.PathError.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, instead of e.g return syscall.SyscallError(err, errno) you can do return &syscall.SyscallError{err, errno} and avoid an unnecessary function call (not sure if golang will inline it). Since this is an internal type, you're not exporting it.

@kolyshkin kolyshkin mentioned this pull request Jul 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants