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

anyhow Errors make it difficult to use this crate #43

Open
schultetwin1 opened this issue Apr 27, 2021 · 8 comments
Open

anyhow Errors make it difficult to use this crate #43

schultetwin1 opened this issue Apr 27, 2021 · 8 comments

Comments

@schultetwin1
Copy link
Contributor

I'm trying to integrate locate-dwarf into my own crate but the usage of anyhow has made it difficult for me to make decisions based on the errors returned. For example, I want to take a different action if an io error occurred in locate_debug_symbols versus if there is no debug pointer to be found.

I'd be willing to change this crate to use thiserror if you are open to it?

@dvc94ch
Copy link
Collaborator

dvc94ch commented Apr 27, 2021

Yes, would be better to return a Result<Option<PathBuf>> as debug info not being available isn't a fatal error.

@schultetwin1 schultetwin1 changed the title anyhow Errors make it to use this crate anyhow Errors make it difficult to use this crate Apr 28, 2021
@luser
Copy link
Collaborator

luser commented Apr 28, 2021

I'd be willing to change this crate to use thiserror if you are open to it?

I had originally used failure, but thiserror is absolutely more useful for library crates.

@dvc94ch
Copy link
Collaborator

dvc94ch commented Apr 28, 2021

I had originally used failure, but thiserror is absolutely more useful for library crates.

That is actually a myth in most cases. The way thiserror is usually abused people put all the possible errors that any code path in a crate could have in an enum and then return it from everywhere. The main argument for thiserror is handling all possible errors and have the compiler check that all cases are handled. Which is a bad argument for one because not all errors are possible in every code path and the wrapping and rewrapping of errors (each library has at least an Io variant) actually makes it harder, and most ways of handling errors involve one of retrying/logging/aborting. And there are a whole host of other reasons why that "rule of thumb" brainlessly applied yields worse results than just using anyhow. You need to capture your backtraces manually which absolutely no one does, it's slower, etc.

And in this case the library is so trivial that an Option is a much better solution anyway. However where thiserror shines is in conveniently deriving Display.

EDIT: sorry if it came of as a little aggressive, I just don't like "wisdom of the crowd" being justified by it's "the wisdom of the crowd". I'm happy to hear why thiserror is perfectly suited for this crate.

@schultetwin1
Copy link
Contributor Author

schultetwin1 commented Apr 29, 2021

sorry if it came of as a little aggressive, I just don't like "wisdom of the crowd" being justified by it's "the wisdom of the crowd". I'm happy to hear why thiserror is perfectly suited for this crate.

No worries, I understand thiserror makes it super easy for someone to just add in all possible errors. That's not what I'm suggesting. I just like thiserror for two reasons (one of which you mentioned).

  1. It derives Display for you
  2. It makes using source very easy (ok... this may be exactly proving your point, but in some cases it's very useful)

And in this case the library is so trivial that an Option is a much better solution anyway.

I started down this path but there are a couple errors that are explicitly handled in this crate. I believe they are ok to switch to Option but would love feedback on that decision. Specifically they are:

  1. The given build-id to locate_debug_build_id is too short.
  2. The parameter path passed into locate_gnu_debuglink can not be canonicalize'd or does not have a parent.
  3. The object::Object variable in locate debug symbols has some error when attempting to read mach_uuid, build_id, or gnu_debuglink.
  4. Rust can't convert the debuglink path to a real path.

For case 1, if the buildid is less than 2 bytes we should return None because it wouldn't be in a .build-id folder anyway.
For case 2, we can return None since a path that did not have a parent would not work for all those searches anyway.
For case 3, these will all occur if the passed in object was corrupted in some way. It might be nice for the user to know that but we could also say " if that data is corrupted, we can't find the dwarf anyway
For case 4, if the path is invalid UTF-8, we won't be able to find the dwarf anyway.

@dvc94ch
Copy link
Collaborator

dvc94ch commented Apr 29, 2021

I'd suggest returning an error if there is corruption or a transient error and None if it isn't found. A transient error would be an io error that could just be ?. For the corruption case it may be worth enumerating the cases like this:

#[derive(Debug, Error)]
pub enum CorruptObject {
    #[error("build id is too short")]
    BuildIdTooShort,
    ...
}

This way if someone really wants to handle the corrupt/transient errors differently they can use downcast_ref::<CorruptObject> or downcast_ref::<std::io::Error> and backtraces are still captured (as the return type would be an anyhow::Result).

@schultetwin1
Copy link
Contributor Author

I've created a PR #49 that partially completes this work. It adds in the Option to the success case of the returned path. But it does not include the custom error object. I'm working on that next.

@luser
Copy link
Collaborator

luser commented Sep 14, 2021

FWIW, having just run into a similar issue attempting to use this crate for a small tool, I can say that at a bare minimum whatever error type this crate returns needs to be exported as part of the public API. At present it's not possible to refer to locate_dwarf::Error.

A bit late, but in re:

I had originally used failure, but thiserror is absolutely more useful for library crates.

That is actually a myth in most cases

I simply meant "failure is unmaintained, thiserror is under active development".

To the original point of this issue: anyhow seems intended for application usage, not library usage, for the "roll all errors up into a single error type" use case. I'm not particularly hung up on this.

@dvc94ch
Copy link
Collaborator

dvc94ch commented Sep 14, 2021

Not really that bothered since I'm not currently using locate-dwarf. But you're not going to convince me that thiserror is better for library crates than anyhow for various reasons I mentioned. It may be that in some cases it's a better fit when done correctly. But if you're just wrapping every error from every dependency in a new enum it's not the case. And please make sure that at least the backtrace is captured and unwrapping an error actually displays were the error was constructed and not where it was unwrapped.

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

No branches or pull requests

3 participants