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

stdlib makes assumptions about errors returned by POSIX functions #94705

Open
tavianator opened this issue Mar 7, 2022 · 13 comments · Fixed by #94712 or #99624
Open

stdlib makes assumptions about errors returned by POSIX functions #94705

tavianator opened this issue Mar 7, 2022 · 13 comments · Fixed by #94712 or #99624
Labels
A-concurrency Area: Concurrency A-error-handling Area: Error handling T-libs Relevant to the library team, which will review and decide on the PR/issue.

Comments

@tavianator
Copy link
Contributor

tavianator commented Mar 7, 2022

Split off from rust-lang/miri#1981 (comment)

For example, we assume that the return value of pthread_rwlock_rdlock() is either 0, EAGAIN, or EDEADLK:

// According to POSIX, for a properly initialized rwlock this can only
// return EAGAIN or EDEADLK or 0. We rely on that.
debug_assert_eq!(r, 0);
self.num_readers.fetch_add(1, Ordering::Relaxed);

And that's kinda what POSIX documents: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_rdlock.html

RETURN VALUE

If successful, the pthread_rwlock_rdlock() function shall return zero; otherwise, an error number shall be returned to indicate the error. ...

ERRORS

... The pthread_rwlock_rdlock() and pthread_rwlock_tryrdlock() functions may fail if:

[EAGAIN]
The read lock could not be acquired because the maximum number of read locks for rwlock has been exceeded.

The pthread_rwlock_rdlock() function may fail if:

[EDEADLK]
A deadlock condition was detected or the current thread already owns the read-write lock for writing.

These functions shall not return an error code of [EINTR].

But the thing is, POSIX error sections are not exhaustive: https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_03

Implementations may generate error numbers listed here under circumstances other than those described, if and only if all those error conditions can always be treated identically to the error conditions as described in this volume of POSIX.1-2017. Implementations shall not generate a different error number from one required by this volume of POSIX.1-2017 for an error condition described in this volume of POSIX.1-2017, but may generate additional errors unless explicitly disallowed for a particular function.

And even the docs for that function mention "shall not return an error code of [EINTR]" rather than "shall not return any other error code". So unless there's limits documented elsewhere, I don't think it's sound to assume that there can't be another error code returned from these functions.

CC: @RalfJung

@RalfJung
Copy link
Member

RalfJung commented Mar 7, 2022

Cc @rust-lang/libs

@cuviper
Copy link
Member

cuviper commented Mar 7, 2022

In general, we should be bubbling up errors that we can't otherwise handle. In this specific instance where we aren't returning Result, we should probably promote that debug assert to a real assert, with a message like "unexpected error: {:?}". If there are others like this, let's treat them on a case-by-case basis.

@yaahc yaahc added A-concurrency Area: Concurrency A-error-handling Area: Error handling E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-help-wanted Call for participation: Help is requested to fix this issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Mar 7, 2022
@kckeiks
Copy link
Contributor

kckeiks commented Mar 7, 2022

@rustbot claim

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Mar 8, 2022
…sumption, r=Mark-Simulacrum

promot debug_assert to assert

Fixes rust-lang#94705
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this issue Mar 8, 2022
…sumption, r=Mark-Simulacrum

promot debug_assert to assert

Fixes rust-lang#94705
@bors bors closed this as completed in a077e44 Mar 8, 2022
@kckeiks
Copy link
Contributor

kckeiks commented Mar 8, 2022

@RalfJung I found these that might be of interest

@RalfJung RalfJung reopened this Mar 8, 2022
@kckeiks
Copy link
Contributor

kckeiks commented Mar 8, 2022

If someone can confirm if we should update all of these functions (promoting assert_debug to assert) then I'll go ahead and open a PR.

@tavianator
Copy link
Contributor Author

Yeah I figured this might be a more general problem than just that one example. I think most of them should become unconditional asserts. It would be helpful if the assertion message included errno (or the returned error code for the pthread functions).

It might be tempting to ignore failures of _destroy() functions in Drop impls, but that can theoretically lead to UB, since the allocation might get re-used and "attempting to initialize an already initialized {mutex,condition variable,...} results in undefined behavior."

These are the special cases I noticed:

let r = unsafe { libc::closedir(self.0) };
debug_assert_eq!(r, 0);

closedir() can return EINTR which should be treated like success. EIO is probably possible too from the underlying close() call and should probably be ignored. I think it's worth checking for EBADF (which would indicate an earlier violation of I/O safety). But it might also be fine to ignore all errors here, like File::drop does.

let ret = unsafe { libc::sched_yield() };
debug_assert_eq!(ret, 0);

It probably doesn't matter if sched_yield() fails, since it has no observable effects (and no one should call it anyway).

@RalfJung
Copy link
Member

RalfJung commented Mar 8, 2022

These are the special cases I noticed:

No strong opinion on what to do with them, but if we opt to not change the code for the reasons you mention, we should still add a comment explaining exactly that.

@kckeiks kckeiks removed their assignment Jun 11, 2022
@vincenzopalazzo
Copy link
Member

This should be fixed in #94712

@RalfJung
Copy link
Member

That fixes one instance of this problem; #94705 (comment) lists a couple more (and I am not sure if that list is exhaustive).

@vincenzopalazzo
Copy link
Member

@rustbot claim

Ok! @RalfJung, I can take a look into it

@bors bors closed this as completed in 569788e Aug 12, 2022
@RalfJung
Copy link
Member

#94705 (comment) lists a lot of these assertions, only 2 or 3 have been changed by the PRs so far I think? Not sure the issue is closed.

@RalfJung RalfJung reopened this Aug 12, 2022
@RalfJung RalfJung removed E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-help-wanted Call for participation: Help is requested to fix this issue. labels Aug 12, 2022
@RalfJung
Copy link
Member

Actually a lot of these links are dead. So the next step probably would be to figure out if there are cases of this left in the stdlib where we assume error lists are exhaustive. A quick search did uncover some:

And there are a whole bunch of debug-only assertions without further comment, listing just a few:

This list is by no means exhaustive.
@rust-lang/libs what is your take on this? So far we only heard from @cuviper that these should become proper assertions, but then when PRs are submitted there often is pushback against that (at least that's what PR authors report). Surprisingly though nobody made any comment in this issue. Cc @Amanieu @thomcc

@vincenzopalazzo
Copy link
Member

vincenzopalazzo commented Aug 13, 2022

@RalfJung Yes this was done in my previous PR #99624 but this not pass the code review! I will open a thread on zulip

Theread link

workingjubilee pushed a commit to tcdi/postgrestd that referenced this issue Sep 15, 2022
promote debug_assert to assert when possible and useful

This PR fixed a very old issue rust-lang/rust#94705 to clarify and improve the POSIX error checking, and some of the checks are skipped because can have no benefit, but I'm sure that this can open some interesting discussion.

Fixes rust-lang/rust#94705

cc: `@tavianator`
cc: `@cuviper`
@vincenzopalazzo vincenzopalazzo removed their assignment Oct 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-concurrency Area: Concurrency A-error-handling Area: Error handling T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
6 participants