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

unexpected behaviour for Custom std::io::Error source implementation #124513

Closed
GlenDC opened this issue Apr 29, 2024 · 1 comment
Closed

unexpected behaviour for Custom std::io::Error source implementation #124513

GlenDC opened this issue Apr 29, 2024 · 1 comment
Labels
C-bug Category: This is a bug.

Comments

@GlenDC
Copy link
Contributor

GlenDC commented Apr 29, 2024

At the time of writing this bug ticket, std::io::Error's source implementation is as follows:

#[stable(feature = "rust1", since = "1.0.0")]
impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self.repr.data() {
            ErrorData::Os(..) => None,
            ErrorData::Simple(..) => None,
            ErrorData::SimpleMessage(..) => None,
            ErrorData::Custom(c) => c.error.source(),
        }
    }
}

If you call:

std::io::Error::new(ErrorKind::Other, MyError).source()

with MyError being defined as:

struct MyError

Then that source will be None.

Seems to me like a bug? How so is there no source?

If you want something deeper, or even as far as the "root cause" then it is up to the user to go deeper, no? Because now let's consider:

struct WrapError(Box<dyn Error + 'static>);
// assuming `WrapError::source` returns `Some(self.0.as_ref())`

And now call:

std::io::Error::new(ErrorKind::Other, WrapError(MyError.into())).source()

Now my source is MyError.

Which means that WrapError is invisible to the user. If you argument is now, great right, because the actual root cause was returned. Well yes, you are correct, but that is only a side-effect and is neither expected and neither will it hold up as soon as you add one more layer...

To be fair I never create std::io::Error myself, I only discovered it as I was using it for a test case out of laziness. It's because I have a custom error module to easily go through the chain of errors, for which I use the source. This has always worked out for me with the assumption that source returns the wrapped error if there is any. And the chain stops when that returns None.

AFAIK that is also what anyhow relies upon, a crate I do not use myself but which is commonly used in the Rust community, so that's why I do reference it here for extra context.

But my chain logic and anyhow's logic alike fails if somewhere in the "chain" there is an std::io::Error. Then again not sure when you would ever look for something lower then the std::io::Error, but I can imagine that some low level http-like crate might use that for some reason? Not sure. Either way, it's behaviour that surprised me.

Whether that's wrong or I am just having wrong assumptions that I am not certain of.

Instead I would expect that source to be implemented as:

#[stable(feature = "rust1", since = "1.0.0")]
impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self.repr.data() {
            ErrorData::Os(..) => None,
            ErrorData::Simple(..) => None,
            ErrorData::SimpleMessage(..) => None,
            // instead of: `c.error.source()`
            ErrorData::Custom(c) => Some(c.error.as_ref()),
        }
    }
}

Which would then correctly give me the next error in the chain (the inner error of std::io::Error.

Meta

rustc --version --verbose:

rustc 1.77.1 (7cf61ebde 2024-03-27)
binary: rustc
commit-hash: 7cf61ebde7b22796c69757901dd346d0fe70bd97
commit-date: 2024-03-27
host: aarch64-apple-darwin
release: 1.77.1
LLVM version: 17.0.6
@GlenDC GlenDC added the C-bug Category: This is a bug. label Apr 29, 2024
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Apr 29, 2024
GlenDC added a commit to GlenDC/rust that referenced this issue Apr 29, 2024
Proposed solution to close rust-lang#124513

Not sure if this should be seen as a breaking change or not.

See for more context rust-lang#124513.
@GlenDC
Copy link
Contributor Author

GlenDC commented Apr 30, 2024

In the PR it wad explained to me that this behaviour was as intended, and I now understand why. Thanks a lot!

@GlenDC GlenDC closed this as not planned Won't fix, can't repro, duplicate, stale Apr 30, 2024
@jieyouxu jieyouxu removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Apr 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants