-
Notifications
You must be signed in to change notification settings - Fork 737
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
fix: insufficient buf size when reading windows named pipe message #1778
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to add a test?
Ah, yeah. Forgot to set up formatting in the windows machine :) |
af53987
to
184703b
Compare
184703b
to
ce98957
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM. Only things I'm wondering are:
- Can we add a test that sends several messages? E.g., generate some sequence of lengths to send, then spawn a background thread that sends messages of those lengths in those orders. Then on the main test thread, receive the messages and assert that the received lengths match.
- Can you run Tokio's test suite with these changes?
We also need @Thomasdezeeuw's ok, but with the above, I would be happy with this PR.
The change passed Tokio's test suites, but the CI is failing on unexpected cfgs. I opened a PR to handle this, unless you have other ideas for the unexpected cfgs @Thomasdezeeuw @Darksonn |
src/sys/windows/named_pipe.rs
Outdated
Err(e) if e.raw_os_error() == Some(ERROR_MORE_DATA as i32) => { | ||
match me.remaining_size() { | ||
Ok(rem) => { | ||
buf.set_len(status.bytes_transferred() as usize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be moved before the call to remaining_size
as those bytes are already read.
return; | ||
} | ||
Err(e) => { | ||
io.read = State::Err(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about this. This makes it an unrecoverable error, but the original error is not. I feel like this is making the situation worse in case PeekNamedPipe
returns an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is the original error recoverable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original ERROR_MORE_DATA
error is not really an error, it we actually read bytes, so it can be ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok, i thought you were referring to the err flow before the change.
Guess we can truncate it in this case
src/sys/windows/named_pipe.rs
Outdated
let mut buf = match mem::replace(&mut io.read, State::None) { | ||
State::None => me.get_buffer(), | ||
State::InsufficientBufferSize(mut buf, rem) => { | ||
buf.reserve_exact(rem); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should have a limit. Otherwise we can allocate large amounts of memory.
0, | ||
std::ptr::null_mut(), | ||
std::ptr::null_mut(), | ||
&mut remaining, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it guaranteed that ERROR_MORE_DATA
is never returned for stream oriented named pipes?
Because according to the PeekNamedPipe
docs (https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe) this will return 0 for streams. Which would mean we're effectively creating an infinite loop where we try to read using a buffer of length 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be surprised if ERROR_MORE_DATA
is ever returned by stream mode named pipe.
But that's a fair point. We can just err out if PeekNamedPipe
returned 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case PeekNamedPipe
returns 0 we should probably just return the short-read buffer, not an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That will happen only when it's stream mode, and we do not expect it to happen, no?
I think we should at least have a debug_assert in this case
Closes tokio-rs/tokio#6460
This PR allows handling
ERROR_MORE_DATA
when the internal buffer size is less than the message in NamedPipe. WhenERROR_MORE_DATA
is hit, the internal buffer will be resized according toPeekNamedPipe
and the remaining message will be read through subsequent call toReadFile
.Also see #1772 for more context.