Skip to content
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

Flush executables to disk after linkage #49432

Merged
merged 3 commits into from
Apr 5, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions src/librustc_trans/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ fn link_natively(sess: &Session,
loop {
i += 1;
prog = time(sess, "running linker", || {
exec_linker(sess, &mut cmd, tmpdir)
exec_linker(sess, &mut cmd, out_filename, tmpdir)
});
let output = match prog {
Ok(ref output) => output,
Expand Down Expand Up @@ -819,7 +819,7 @@ fn link_natively(sess: &Session,
}
}

fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path)
fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &Path)
-> io::Result<Output>
{
// When attempting to spawn the linker we run a risk of blowing out the
Expand All @@ -833,7 +833,11 @@ fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path)
// there instead of looking at the command line.
if !cmd.very_likely_to_exceed_some_spawn_limit() {
match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
Ok(child) => return child.wait_with_output(),
Ok(child) => {
let output = child.wait_with_output();
flush_linked_file(&output, out_filename)?;
return output;
}
Err(ref e) if command_line_too_big(e) => {
info!("command line to linker was too big: {}", e);
}
Expand Down Expand Up @@ -867,7 +871,37 @@ fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path)
fs::write(&file, &bytes)?;
cmd2.arg(format!("@{}", file.display()));
info!("invoking linker {:?}", cmd2);
return cmd2.output();
let output = cmd2.output();
flush_linked_file(&output, out_filename)?;
return output;

#[cfg(unix)]
fn flush_linked_file(_: &io::Result<Output>, _: &Path) -> io::Result<()> {
Ok(())
}

#[cfg(windows)]
fn flush_linked_file(command_output: &io::Result<Output>, out_filename: &Path)
-> io::Result<()>
{
// On Windows, under high I/O load, output buffers are sometimes not flushed,
// even long after process exit, causing nasty, non-reproducible output bugs.
//
// File::sync_all() calls FlushFileBuffers() down the line, which solves the problem.
//
// А full writeup of the original Chrome bug can be found at
// randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/amp

if let &Ok(ref out) = command_output {
if out.status.success() {
if let Ok(of) = fs::OpenOptions::new().write(true).open(out_filename) {
of.sync_all()?;
}
}
}

Ok(())
}

#[cfg(unix)]
fn command_line_too_big(err: &io::Error) -> bool {
Expand Down