Skip to content

Cap socket send length to c_int::MAX on Apple targets#159530

Open
devnexen wants to merge 4 commits into
rust-lang:mainfrom
devnexen:gh115325
Open

Cap socket send length to c_int::MAX on Apple targets#159530
devnexen wants to merge 4 commits into
rust-lang:mainfrom
devnexen:gh115325

Conversation

@devnexen

@devnexen devnexen commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

On Apple, send/sendto reject a length larger than c_int::MAX with EINVAL instead of doing a short send. The send length was only clamped to wrlen_t::MAX (a no-op on 64-bit unix), so writing more than c_int::MAX bytes to a socket failed on macOS.

Add a MAX_SEND_LEN cap (c_int::MAX on Apple, wrlen_t::MAX elsewhere), used in write, send, send_to, and send_with_flags.

Fixes #115325

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jul 18, 2026
@rustbot

rustbot commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

r? @Darksonn

rustbot has assigned @Darksonn.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 13 candidates
  • Random selection from 6 candidates

@rustbot

This comment has been minimized.

Comment thread library/std/src/net/tcp/tests.rs Outdated
// macOS with `EINVAL`; `write_all` should now transfer it via short sends.
#[test]
#[cfg(target_pointer_width = "64")]
#[ignore = "allocates ~2 GiB and transfers it over loopback"]

@Mark-Simulacrum Mark-Simulacrum Jul 18, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is the ignore because this is very slow? Is that the TCP side or the allocation?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

A bit of both but mostly the memory allocation, the client allocates a buffer of c_int::MAX + 1 (~2 GiB); the reader only uses a 1 MiB scratch buffer.

Comment thread library/std/src/net/tcp/tests.rs Outdated
Err(e) => panic!("read error: {e}"),
}
}
t!(tx.send(received));

@Mark-Simulacrum Mark-Simulacrum Jul 18, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do we need a channel instead of just returning received from the thread and asserting this on join?

View changes since the review

On Apple, `send`/`sendto` reject a length larger than `c_int::MAX` with
`EINVAL` instead of doing a short send. The send length was only clamped to
`wrlen_t::MAX` (a no-op on 64-bit unix), so writing more than `c_int::MAX`
bytes to a socket failed on macOS.

Add a `MAX_SEND_LEN` cap (`c_int::MAX` on Apple, `wrlen_t::MAX` elsewhere),
used in `write`, `send`, `send_to`, and `send_with_flags`.

pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
let len = cmp::min(buf.len(), MAX_SEND_LEN) as wrlen_t;

@bjorn3 bjorn3 Jul 18, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For datagram sockets like UDP isn't inability to send it as atomic message supposed to result in EMSGSIZE? Truncating the buffer would be incorrect though truncating to i32::MAX will probably still happen to work as UDP doesn't support packets larger than 64k and thus still result in EMSGSIZE for an i32::MAX sized buffer. I think it would be better to return an explicit EMSGSIZE when the buffer is too large though.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It can't truncate a datagram: anything over i32::MAX already exceeds the max message size, so both the full and clamped length fail with EMSGSIZE — on macOS the clamp just turns EINVAL into EMSGSIZE. Happy to add an explicit EMSGSIZE if you'd prefer, but it'd cost a SO_TYPE syscall per send.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

but it'd cost a SO_TYPE syscall per send.

Why?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

nevermind :) I misread the code layout..

@rust-log-analyzer

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Socket error on MacOS when sending huge buffers over TCP socket

6 participants