miri icon indicating copy to clipboard operation
miri copied to clipboard

Complete socketpair support

Open RalfJung opened this issue 3 months ago • 5 comments

We pretend to implement socketpair, but that's a complete lie. Completing this however doesn't need any involvement with the rest of the epoll plans. We "just" need to allocate somewhere two buffers for the data to be sent between these two endpoints, and then wire up the read/write of the two sockets with the right buffers. This can be tested by directly using socketpair/read/write.

There's also https://github.com/rust-lang/miri/issues/3231.

We can provide more detailed mentoring instructions if needed.

RalfJung avatar Apr 03 '24 07:04 RalfJung

I think this should follow the proposed "project" process: https://github.com/rust-lang/miri/issues/3443.

RalfJung avatar Apr 03 '24 09:04 RalfJung

I wonder if there are libc compliance test suites that are licensed well enough for us to extract tests from

oli-obk avatar Apr 03 '24 09:04 oli-obk

Hi, I am planning to work on this first since it is related to #3448. I will send the link to the proposal here once I finished localtime_r.

tiif avatar Apr 05 '24 15:04 tiif

@rustbot claim

tiif avatar Apr 17 '24 08:04 tiif

Error: The feature assign is not enabled in this repository. To enable it add its section in the triagebot.toml in the root of the repository.

Please file an issue on GitHub at triagebot if there's a problem with this bot, or reach out on #t-infra on Zulip.

rustbot avatar Apr 17 '24 08:04 rustbot

I wonder if there are libc compliance test suites that are licensed well enough for us to extract tests from

Hmm I couldn't find any test for libc for now, if anyone knows where can I find one please let me know, thanks. Currently I imagine minimally the test should look like this (Note: they wrapped libc around their API, so it looks slightly different)

#[test]
pub fn test_socketpair() {
    use nix::sys::socket::{socketpair, AddressFamily, SockFlag, SockType};
    use nix::unistd::{read, write};

    let (fd1, fd2) = socketpair(
        AddressFamily::Unix,
        SockType::Stream,
        None,
        SockFlag::empty(),
    )
    .unwrap();
    write(&fd1, b"hello").unwrap();
    let mut buf = [0; 5];
    read(fd2.as_raw_fd(), &mut buf).unwrap();

    assert_eq!(&buf[..], b"hello");
}
//source: https://github.com/nix-rust/nix/blob/590ab4d5d0b6228f0529b036e4f8a42265ba6d31/test/sys/test_socket.rs#L311. 

source: nix-rust/nix

I might add similar test in the proposal that I am going to send soon.

tiif avatar Apr 30 '24 19:04 tiif

This is the proposal for socketpair shim: https://hackmd.io/@tiif/Skhc1t0-C. It is still under development, more attention is needed for the problems below:

  1. Should we block write when the buffer is full?
  2. How can miri differentiate read and write of socketpair file descriptors and other kind of file descriptors?

Feel free to provide any ideas or suggestion especially for the buffer mechanism part.

tiif avatar May 03 '24 10:05 tiif

2. How can miri differentiate read and write of socketpair file descriptors and other kind of file descriptors?

Why does it need to? Shouldn't the abstraction provided by the FileDescriptor trait hide all thatvand only the socket pair type implementing that trait would care?

oli-obk avatar May 03 '24 10:05 oli-obk

Left some comments,on the doc

oli-obk avatar May 03 '24 10:05 oli-obk

Should we block write when the buffer is full?

Yes, we should.

How can miri differentiate read and write of socketpair file descriptors and other kind of file descriptors?

As Oli said: you "just" have to implement the read and write functions of the SocketPair type; the general file descriptor machinery will make sure to dispatch to that when read/write is called on an FD that is (part of) a socketpair.

RalfJung avatar May 03 '24 17:05 RalfJung

This is the proposal for socketpair shim: https://hackmd.io/@tiif/Skhc1t0-C. It is still under development, more attention is needed for the problems below:

Thanks! The API description is very helpful. I have left some comments.

What is missing for me is a plan for how the Miri state looks like. In particular, the proposal should say what the fields of struct SocketPair will be. I currently think it will likely be something like

struct SocketPair {
  write_buf: Rc<SocketBuf>,
  read_buf: Rc<SocketBuf>,
}

but that then raises the question of what the fields of SocketBuf are. :) Maybe data: VecDeque<u8> as you sketched out is sufficient.

RalfJung avatar May 03 '24 18:05 RalfJung

FWIW, once this is done it should be fairly easy to also support pipe/pipe2. Those are basically just one-directional sockets, for our purposes.

RalfJung avatar May 07 '24 08:05 RalfJung