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

Enforce OS errors are in the allowed range. #441

Merged
merged 1 commit into from
Jun 4, 2024

Conversation

briansmith
Copy link
Contributor

@briansmith briansmith commented May 31, 2024

Avoid the From<NonZeroU32> implementation in favor of a constructor that centralizes all the range checking in one place. Consistently use ERRNO_NOT_POSITIVE for nonpositive values and Self::UNEXPECTED for too-large values.

Besides being more consistent in the range checking, this also reduces the boilerplate in callers, which makes it easier to maintain the ports to less-common operating systems.

src/error.rs Outdated
@@ -65,6 +65,19 @@ impl Error {
/// custom errors.
pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30);

#[cold]
pub(super) fn new_os(code: u32) -> Self {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the future we might consider adding a public new_custom constructor and then deprecating the From<NonZeroU32> that does the non-range-checked conversion.

@briansmith briansmith force-pushed the b/new_os branch 3 times, most recently from 53d8f46 to 0af5ac5 Compare June 4, 2024 17:09
@briansmith
Copy link
Contributor Author

I updated this to be cleaner. I also removed the #[cold] since that's an unrelated change.

@newpavlov
Copy link
Member

What about my suggestion above?

@briansmith
Copy link
Contributor Author

What about my suggestion above?

Sorry, I don't see it. Maybe it is still a draft?

@newpavlov
Copy link
Member

Oh, oops. You are right.

src/error.rs Outdated
@@ -65,6 +65,20 @@ impl Error {
/// custom errors.
pub const CUSTOM_START: u32 = (1 << 31) + (1 << 30);

#[allow(dead_code)]
#[cold]
pub(super) fn new_os(code: u32) -> Self {
Copy link
Member

Choose a reason for hiding this comment

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

Could you add some docs for this method?

I also think we can write it like this:

pub(crate) fn from_os_code(code: impl TryInto<u32>) -> Self {
    code.try_into()
        .ok()
        .and_then(NonZeroU32::new)
        .and_then(|code| {
            if code.get() < Self::INTERNAL_START {
                Some(Self(code))
            } else {
                None
            }
        })
        .unwrap_or(Self::UNEXPECTED)
}

This will make backend code a bit nicer.

I don't think we need to distinguish between ERRNO_NOT_POSITIVE and UNEXPECTED. Both cases should never happen in practice in the first place. Plus the former was used only for codes from errno.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could you add some docs for this method?

OK. But...

pub(crate) fn from_os_code(code: impl TryInto) -> Self {

Unfortunately that would allow passing a usize or similar, which really shouldn't be implicitly converted. So I think we should not do that.

I don't think we need to distinguish between ERRNO_NOT_POSITIVE and UNEXPECTED

I am OK with making that change.

Copy link
Member

Choose a reason for hiding this comment

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

Unfortunately that would allow passing a usize or similar, which really shouldn't be implicitly converted.

Since it's a private API, I think it's fine to allow this. If you want to make this more explicit, you could use Error::from_os_code::<isize>(code) at call sites. Either way, I do not insist on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, I think the main goal here is to ensure that the result is well-defined, rather than to increase convenience.

I do hope this API can be improved further and then made public to replace the From<NonZeroU32> implementation as discussed elsewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added the documentation, moved the ERRNO_NOT_POSITIVE logic back to where it belongs, and renamed the function to be more like the analogous std::io::Error function.

@briansmith briansmith force-pushed the b/new_os branch 2 times, most recently from 5391cbc to 52bcd6d Compare June 4, 2024 23:20
Avoid the `From<NonZeroU32>` implementation in favor of a constructor
that centralizes all the range checking in one place. Consistently use
 `Self::UNEXPECTED` for out-of-rnage values.

Besides being more consistent in the range checking, this also reduces
the boilerplate in callers, which makes it easier to maintain the ports
to less-common operating systems.

This is a step towards deprecating the `impl From<NonZeroU32> for Error`
implementation.
@newpavlov newpavlov merged commit 05cdf6f into rust-random:master Jun 4, 2024
52 checks passed
@briansmith briansmith deleted the b/new_os branch June 4, 2024 23:36
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.

2 participants