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

Use/fix ret_* helpers for certain libc functions #1212

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

pinotree
Copy link

@pinotree pinotree commented Nov 9, 2024

  • use ret_usize() instead of ret_send_recv() for c::recvmsg(), as it always returns c::ssize_t
  • use ret_usize() instead of ret_send_recv() for c::sendmsg(), as it always returns c::ssize_t
  • change the ret_send_recv() used on OSes different than Windows, Redox, and wasi to take c::ssize_t as parameter, as it is what c::recv(), c::send(), c::recvfrom(), and c::sendto() return on most/all of those OSes

- use ret_usize() instead of ret_send_recv() for c::recvmsg(), as it
  always returns c::ssize_t
- use ret_usize() instead of ret_send_recv() for c::sendmsg(), as it
  always returns c::ssize_t
- change the ret_send_recv() used on OSes different than Windows,
  Redox, and wasi to take c::ssize_t as parameter, as it is what
  c::recv(), c::send(), c::recvfrom(), and c::sendto() return on
  most/all of those OSes
@sunfishcode
Copy link
Member

  • use ret_usize() instead of ret_send_recv() for c::recvmsg(), as it always returns c::ssize_t

    • use ret_usize() instead of ret_send_recv() for c::sendmsg(), as it always returns c::ssize_t

Windows doesn't have sendmsg/recvmsg, however send/recv return i32 instead of ssize_t. WSASendMsg isn't directly analogous to POSIX sendmsg, but it returns its number of bytes as an i32 as well. So it seems that ret_send_recv is the right thing to use for these.

* change the `ret_send_recv()` used on OSes different than Windows, Redox, and wasi to take `c::ssize_t` as parameter, as it is what `c::recv()`, `c::send()`, `c::recvfrom()`, and `c::sendto()` return on most/all of those OSes

This part sounds good.

@pinotree
Copy link
Author

pinotree commented Nov 9, 2024

Windows doesn't have sendmsg/recvmsg, however send/recv return i32 instead of ssize_t. WSASendMsg isn't directly analogous to POSIX sendmsg, but it returns its number of bytes as an i32 as well. So it seems that ret_send_recv is the right thing to use for these.

Right, there is the Windows version of ret_send_recv() already that does that:

/// Convert the return value of a `send` or `recv` call.
#[cfg(windows)]
#[inline]
pub(super) fn ret_send_recv(len: i32) -> io::Result<usize> {
ret_usize(len as isize)
}

Did I miss anything? 🤔

@sunfishcode
Copy link
Member

Windows doesn't have sendmsg/recvmsg, however send/recv return i32 instead of ssize_t. WSASendMsg isn't directly analogous to POSIX sendmsg, but it returns its number of bytes as an i32 as well. So it seems that ret_send_recv is the right thing to use for these.

Right, there is the Windows version of ret_send_recv() already that does that:

/// Convert the return value of a `send` or `recv` call.
#[cfg(windows)]
#[inline]
pub(super) fn ret_send_recv(len: i32) -> io::Result<usize> {
ret_usize(len as isize)
}

Did I miss anything? 🤔

Because of that, ret_send_recv is already the right function to use for converting the return values of sendmsg and recvmsg.

@pinotree
Copy link
Author

pinotree commented Nov 9, 2024

Because of that, ret_send_recv is already the right function to use for converting the return values of sendmsg and recvmsg.

Not really:

  • sendmsg() and recvmsg() return ssize_t in their POSIX standard definitions [1][2]
  • all the implementations of sendmsg() and recvmsg() in the libc crate return ssize_t
  • in the libc create, the Hurd implementation does not have ssize_t == isize but ssize_t == c_int

While the different type of libc::ssize_t on Hurd might be an issue, I think that rustix ought to use the right type of sendmsg() and recvmsg() in libc which is libc::ssize_t, without relying on type equivalence.

[1] https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html
[2] https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html

@sunfishcode
Copy link
Member

Windows doesn't follow POSIX. It uses i32. ret_send_recv can take an ssize_t on POSIX platforms, and it takes an i32 on Windows, so it's the right function to use.

@pinotree
Copy link
Author

ret_send_recv can take an ssize_t on POSIX platforms,

As I said earlier, this only works when ssize_t is defined in the libc crate as isize, which happens on almost all the unix-ish platforms. On 32bit Hurd, ssize_t is defined as i32, which is not equivalent to isize, and thus building something that uses rustix fails:

error[E0308]: mismatched types
   --> /usr/share/cargo/registry/rustix-0.38.37/src/backend/libc/net/syscalls.rs:367:23
    |
367 |           ret_send_recv(c::sendmsg(
    |  _________-------------_^
    | |         |
    | |         arguments to this function are incorrect
368 | |             borrowed_fd(sockfd),
369 | |             &msghdr,
370 | |             bitflags_bits!(msg_flags),
371 | |         ))
    | |_________^ expected `isize`, found `i32`

Hence this PR:

  • since sendmsg() and recvmsg() are not implemented on Windows, and sendmsg() and recvmsg() in the libc rustix backend are not implemented on Windows, their usage is unconditionally switched to ret_usize(), which (despite the name) takes c::ssize_t
  • regarding the other send/recv functions: since ret_send_recv() has already a version for Windows (which is not changed by this PR), the non-Windows version is switched to use c::ssize_t instead

So there should be no changes for Windows, and indeed the CI jobs for Windows pass.

@sunfishcode
Copy link
Member

I'm confused about what's going on on hurd. This standalone program:

$ cat src/main.rs 
fn main() {
    unsafe {
        let _t: ::libc::ssize_t = ::libc::sendmsg(0, core::ptr::null(), 0);
    }
}

compiled for 32-bit hurd gets an error:

$ cargo +nightly check --target=i686-unknown-hurd-gnu -Zbuild-std 
    Checking t v0.1.0 (...)
error[E0308]: mismatched types
 --> src/main.rs:3:35
  |
3 |         let _t: ::libc::ssize_t = ::libc::sendmsg(0, core::ptr::null(), 0);
  |                 ---------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `i32`
  |                 |
  |                 expected due to this
  |
help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit
  |
3 |         let _t: ::libc::ssize_t = ::libc::sendmsg(0, core::ptr::null(), 0).try_into().unwrap();
  |                                                                           ++++++++++++++++++++

For more information about this error, try `rustc --explain E0308`.

In the libc crate's source code, hurd's sendmsg appears to be declared to return an ssize_t:

    pub fn sendmsg(__fd: ::c_int, __message: *const msghdr, __flags: ::c_int) -> ::ssize_t;

Why does rustc think that this ssize_t is an i32, when the other ssize_t is an isize?

@sunfishcode
Copy link
Member

Also, your branch doesn't build on hurd either:

    Checking rustix v0.38.35 (...)
error[E0308]: mismatched types
   --> src/backend/libc/net/syscalls.rs:369:19
    |
369 |           ret_usize(c::sendmsg(
    |  _________---------_^
    | |         |
    | |         arguments to this function are incorrect
370 | |             borrowed_fd(sockfd),
371 | |             &msghdr,
372 | |             bitflags_bits!(msg_flags),
373 | |         ))
    | |_________^ expected `isize`, found `i32`
    |
note: function defined here
   --> src/backend/libc/conv.rs:88:15
    |
88  | pub(super) fn ret_usize(raw: c::ssize_t) -> io::Result<usize> {
    |               ^^^^^^^^^ ---------------
help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit
    |
373 |         ).try_into().unwrap())
    |          ++++++++++++++++++++

...

@sunfishcode
Copy link
Member

It looks like rust-lang/libc#4029 will change hurd's ssize_t to be an alias for isize.

@sunfishcode
Copy link
Member

So in summary here,

  • sendmsg and recvmsg should continue to use ret_send_recv.
  • ret_send_recv could take an ssize_t instead of an isize.

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