-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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 a very minor race condition in cargo fix
.
#6515
Conversation
r? @Eh2406 (rust_highfive has picked a reviewer for you, use r? to override) |
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.
LGTM
Should this have some kind of test? Not that I know how to make one... |
r=me, after the test chat. |
To make sure I understand the race here, the problem is that we closed the client connection too early, which allow the client (the If that's all the case I think it's fine to avoid a test here, spurious failures are showing we're already covering this :) |
if done.load(Ordering::SeqCst) { | ||
break; | ||
} | ||
let mut client = BufReader::new(client); |
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.
FWIW with read_to_string
the BufReader
here is likely no longer necessary
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 looked at that for a bit. It didn't seem too important, but if I understand the code correctly, a bare read_to_string uses a 32-byte buffer whereas BufReader uses an 8k buffer. Does that sound correct? Sometimes it's difficult to trace with various different traits involved. read_to_end_with_reservation
doesn't appear to grow its read size, which is a little surprising.
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.
Eh it could go either way I think. read_to_string
starts with 32 bytes and exponentially increases (IIRC) and also avoids zeroing and does other fancy tricks. Ideally we'd reuse a buffer here but this isn't really performance sensitive anyway so it doesn't matter too much. Whichever you feel like doing is fine by me!
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.
Oh, indeed, it does 32,32,64,128,256,... (I'm guessing it's this). I'm fine with leaving it as-is, saves a few round trips in the common case (large text messages).
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 it's actually this one, but it's morally the same thing!
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.
Oh, I was just looking at the end of that call chain, because read_to_end_with_reservation
does not do any obvious doubling (and the behavior does not appear to be documented anywhere). I'm assuming the call g.buf.reserve(32)
goes to RawVec::reserve
which goes to reserve_internal
with the Amortized
strategy to amortized_new_size
which does the doubling (and the needed_extra_cap
of 32 gets ignored pretty quickly).
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.
er oops, right!
The test is diff --git a/src/cargo/util/diagnostic_server.rs b/src/cargo/util/diagnostic_server.rs
index e7e1aff1..39140504 100644
--- a/src/cargo/util/diagnostic_server.rs
+++ b/src/cargo/util/diagnostic_server.rs
@@ -266,6 +266,8 @@ impl RustfixDiagnosticServer {
if let Err(e) = client.read_to_string(&mut s) {
warn!("diagnostic server failed to read: {}", e);
} else {
+ drop(client);
+ std::thread::sleep(std::time::Duration::from_millis(1000));
match serde_json::from_str(&s) {
Ok(message) => on_message(message),
Err(e) => warn!("invalid diagnostics message: {}", e),
@@ -274,7 +276,6 @@ impl RustfixDiagnosticServer {
// The client should be kept alive until after `on_message` is
// called to ensure that the client doesn't exit too soon (and
// Message::Finish getting posted before Message::FixDiagnostic).
- drop(client);
}
}
} and run |
Yes, everything you said is correct. |
@bors: r+ |
📌 Commit 7584dce has been approved by |
Fix a very minor race condition in `cargo fix`. There is a very rare race where a "fix" message was getting posted *after* `Message::Finish`, and thus being dropped without being printed. This is caused by the diagnostic server disconnecting the client before posting `Message::FixDiagnostic`. The solution is to keep the client on the line until after the message is posted. Fixes some errors in `fixes_missing_ampersand` seen in CI: https://travis-ci.org/rust-lang/cargo/jobs/474384359 https://travis-ci.org/rust-lang/cargo/jobs/429809800 I also moved the `done` check to the beginning of the loop because every time the server was shut down it was needlessly trying to parse an empty string (and failing).
☀️ Test successful - status-appveyor, status-travis |
Update cargo 24 commits in 0d1f1bbeabd5b43a7f3ecfa16540af8e76d5efb4..34320d212dca8cd27d06ce93c16c6151f46fcf2e 2018-12-19 14:45:14 +0000 to 2019-01-03 19:12:38 +0000 - Display environment variables for rustc commands (rust-lang/cargo#6492) - Fix a very minor race condition in `cargo fix`. (rust-lang/cargo#6515) - Add a high-level overview of how `fix` works. (rust-lang/cargo#6516) - Add dependency `registry` to `cargo metadata`. (rust-lang/cargo#6500) - Fix fingerprint calculation for patched deps. (rust-lang/cargo#6493) - serialize version directly (rust-lang/cargo#6512) - use DYLD_FALLBACK_LIBRARY_PATH for dylib_path_envvar on macOS (rust-lang/cargo#6355) - Fix error message when resolving dependencies (rust-lang/cargo#6510) - use PathBuf in cargo metadata (rust-lang/cargo#6511) - Fixed link to testsuite in CONTRIBUTING.md (rust-lang/cargo#6506) - Update display of contents of Cargo.toml (rust-lang/cargo#6501) - Update display of contents of Cargo.toml (rust-lang/cargo#6502) - Fixup cargo install's help message (rust-lang/cargo#6495) - testsuite: Require failing commands to check output. (rust-lang/cargo#6497) - Delete unnecessary 'return' (rust-lang/cargo#6496) - Fix new unused patch warning. (rust-lang/cargo#6494) - Some minor documentation changes. (rust-lang/cargo#6481) - Add `links` to `cargo metadata`. (rust-lang/cargo#6480) - Salvaged semver work (rust-lang/cargo#6476) - Warn on unused patches. (rust-lang/cargo#6470) - don't write a an incorrect rustc version to the fingerprint file (rust-lang/cargo#6473) - Rewrite `login` and registry cleanups. (rust-lang/cargo#6466) - [issue#6461] Fix cargo commands list (rust-lang/cargo#6462) - Restrict registry names to same style as package names. (rust-lang/cargo#6469)
There is a very rare race where a "fix" message was getting posted after
Message::Finish
, and thus being dropped without being printed. This is caused by the diagnostic server disconnecting the client before postingMessage::FixDiagnostic
. The solution is to keep the client on the line until after the message is posted.Fixes some errors in
fixes_missing_ampersand
seen in CI:https://travis-ci.org/rust-lang/cargo/jobs/474384359
https://travis-ci.org/rust-lang/cargo/jobs/429809800
I also moved the
done
check to the beginning of the loop because every time the server was shut down it was needlessly trying to parse an empty string (and failing).