Uh oh!
There was an error while loading. Please reload this page.
Fix windows Socket::connect_timeout overflow - #112464
Conversation
rustbot
commented
Jun 9, 2023
r? @thomcc (rustbot has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
bb125c5 to
80b5ea8Compareeval-exec
commented
Jun 9, 2023
@rustbot review |
Uh oh!
There was an error while loading. Please reload this page.
26720ce to
845c89cCompareChrisDenton
commented
Jun 10, 2023
This looks good to me.
This is a bit more tricky but I think the easiest way would be to copy/paste |
This comment has been minimized.
This comment has been minimized.
1e6a863 to
e23346bCompare
This comment has been minimized.
This comment has been minimized.
e23346b to
2953b71Compare
This comment has been minimized.
This comment has been minimized.
2953b71 to
fc4cff2Compare
This comment has been minimized.
This comment has been minimized.
fc4cff2 to
7bac07dCompare7bac07d to
11df849CompareThere was a problem hiding this comment.
Have you confirmed this test fails without the changes in net.rs?
There was a problem hiding this comment.
@eval-exec for an alternative idea of what a test could do:
- bind some free port on localhost using
TcpListener::bind, then - connect to that new port with
Duration::MAXtimeout.
Here's a draft in Rust:
use std::net::TcpListener;let listener = TcpListener::bind("127.0.0.1:0").unwrap();// :0 picks some free portlet port = listener.local_addr().unwrap().port();// obtain the port it picked[..][..]format!("127.0.0.1:{port}").as_str()[..]// connect to that portI have a real example of something very close at https://github.com/hartwork/rust-for-it/blob/4e51982c4465c3190d92a59747c5d2738baf9e07/src/network.rs#L160-L177 .
What do you think?
There was a problem hiding this comment.
Thank you, I'm testing it on a win10 virtual machine.
There was a problem hiding this comment.
@eval-exec I checked the latest version: 0.0.0.0:1 will only work if you start a TCP listener on port 1. And port 1 only works if it's unoccupied and you have privileges because ports up to 1024 are reserved. In a test context you'll probably want a dynamic free port as in my example above.
There was a problem hiding this comment.
I'm confused, I try to connect to an unreachable address 8.8.8.8:9999, but it didn't get timeout.
There was a problem hiding this comment.
@eval-exec updated twice more (in case you only saw the version sent via notification e-mail)
There was a problem hiding this comment.
It should be format!("0.0.0.0:{port}" or format!("127.0.0.1:{port}" for connect_timeout?
There was a problem hiding this comment.
@eval-exec I would argue for 127.0.0.1 for clarity. Both work in practice.
There was a problem hiding this comment.
I think I should bind and accept in another thread:
#[test]fnconnect_timeout_ok_bind(){let socket_addr = next_test_ip4();
thread::spawn({let listener = t!(TcpListener::bind(&socket_addr));move || {letmut stream = t!(listener.accept()).0;letmut buf = [0];t!(stream.read(&mut buf));}});assert!(TcpStream::connect_timeout(&socket_addr,Duration::MAX).is_ok());}There was a problem hiding this comment.
I think I should
bindandacceptin another thread:
@eval-exec that's not necessary, see https://github.com/hartwork/rust-for-it/blob/4e51982c4465c3190d92a59747c5d2738baf9e07/src/network.rs#L160-L177 .
thomcc
commented
Jun 17, 2023
Chris seems like he's reviewing this. r? @ChrisDenton |
11df849 to
7871e56Compare
This comment has been minimized.
This comment has been minimized.
a4cce33 to
ca83467Compare
This comment has been minimized.
This comment has been minimized.
ChrisDenton
commented
Jun 17, 2023
The failure condition in your issue was "Instead, this happened: the call never succeeds, not even for google.com:80 on Windows." That is not infinite blocking. |
hartwork
commented
Jun 17, 2023
@ChrisDenton maybe I should have put it more clearly: by "never succeeds" I meant that it should have returned success quickly for google.com:80 but instead it blocked forever and hence never finishes to return with due success. Given your spot-on early analysis at #112405 (comment) I do not understand how we have different understanding now. I'd be happy to learn what I a missing now. Are there two bugs here instead of a single one? |
hartwork
commented
Jun 17, 2023
@ChrisDenton PS: The CI at https://github.com/hartwork/rust-for-it/actions/runs/5204380736/jobs/9388510541 was cancelled by GitHub after near-exact 6 hours runtime due to that call while google.com:80 was available. |
eval-exec
commented
Jun 18, 2023
What's the related code of this canceled CI action? |
@eval-exec that would effectively be https://github.com/hartwork/rust-for-it/tree/4c816e51eb8134cef32571400f5583e3f75cec54 or: git clone https://github.com/hartwork/rust-for-it
cd rust-for-it
git checkout 4c816e51eb8134cef32571400f5583e3f75cec54 |
connect to a reachable address:use std::net::{TcpStream,ToSocketAddrs};use std::time::Duration;fnmain(){let address_result = "1.1.1.1:80".to_socket_addrs();let address = address_result.unwrap().next().unwrap();TcpStream::connect_timeout(&address,Duration::MAX).expect("connect_timeout");println!("main fn returned");}
connect to an unreachable address:use std::net::{TcpStream,ToSocketAddrs};use std::time::Duration;fnmain(){let address_result = "1.1.1.1:9999".to_socket_addrs();let address = address_result.unwrap().next().unwrap();TcpStream::connect_timeout(&address,Duration::MAX).expect("connect_timeout");println!("main fn returned");}
|
So, I think I can add a unit test: connect to an unreachable address like #[test]fnconnect_timeout_to_unreachable_address(){let now = Instant::now();let result =
TcpStream::connect_timeout(&format!("1.1.1.1:9999").parse().unwrap(),Duration::MAX);assert!(matches!(result,ErrorKind::TimedOut));assert!(now.elapsed() > Duration::from_secs(20));}What do you think? @hartwork@ChrisDenton |
ChrisDenton
commented
Jun 18, 2023
@hartwork the reason your CI ran indefinitely is because you have an infinite loop. if running only the code in the issue, it errors immediately. |
13c995c to
bf52e9bCompare
This comment has been minimized.
This comment has been minimized.
Signed-off-by: Eval EXEC <execvy@gmail.com>
bf52e9b to
f65b5d0Compare| } | ||
| #[test] | ||
| fn connect_timeout_to_unreachable_address() { |
There was a problem hiding this comment.
I tested, this unit test will cost at 2 minutes and 8 seconds on Linux platform, and cost 20 seconds on Windows.
There was a problem hiding this comment.
I think we only need one test here. We only need to focus on testing the problematic code path in one way. 2 minutes and 8 secs is a long time for a single unit test so I'd prefer if we just used connect_timeout_error test and removed the other two.
There was a problem hiding this comment.
Ok, I think 2 minutes and 8 seconds is a long time too.
hartwork
commented
Jun 18, 2023
@ChrisDenton thanks for clearing this up, you're 100% right, I was able to confirm your results in GitHub Actions now. Sorry 🙏 |
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Chris Denton <christophersdenton@gmail.com>
ChrisDenton
left a comment
There was a problem hiding this comment.
This looks great to me, thanks! Sorry testing end up being so involved.
ChrisDenton
commented
Jun 20, 2023
@bors r+ rollup |
bors
commented
Jun 20, 2023
eval-exec
commented
Jun 20, 2023
via email
Thank you. …On Tue, Jun 20, 2023 at 6:57 PM Chris Denton ***@***.***> wrote:
***@***.**** approved this pull request.
This looks great to me, thanks! Sorry testing end up being so involved.
—
Reply to this email directly, view it on GitHub
<#112464 (review)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ALCAINR7SJLSDNMQPA2SILLXMF6ZRANCNFSM6AAAAAAZAVVJSE>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
…llaumeGomez Rollup of 6 pull requests Successful merges: - rust-lang#112464 (Fix windows `Socket::connect_timeout` overflow) - rust-lang#112720 (Rustdoc: search: color item type and reduce size to avoid clashing) - rust-lang#112762 (Sort the errors from arguments checking so that suggestions are handled properly) - rust-lang#112786 (change binders from tuple structs to named fields) - rust-lang#112794 (Fix linker failures when #[global_allocator] is used in a dependency) - rust-lang#112819 (Disable feature(unboxed_closures, fn_traits) in weird-exprs) r? `@ghost` `@rustbot` modify labels: rollup
| fn connect_timeout_error() { | ||
| let socket_addr = next_test_ip4(); | ||
| let result = TcpStream::connect_timeout(&socket_addr, Duration::MAX); | ||
| assert!(!matches!(result, Err(e) if e.kind() == ErrorKind::TimedOut)); |
There was a problem hiding this comment.
This is a strange test. It says to only timeout after billions of years, yet apparently it expects the OS to timeout immediately. What is going on here? And why is there no comment explaining this?^^
Context: #156385
There was a problem hiding this comment.
Hello, I reviewed your PR. Is there some tasks we can do next for further steps?
There was a problem hiding this comment.
If the comment there makes sense then I think that's all, thanks :)
This PR want to close#112405