Skip to content

Commit

Permalink
Rollup merge of rust-lang#49432 - nabijaczleweli:master, r=michaelwoe…
Browse files Browse the repository at this point in the history
…rister

Flush executables to disk after linkage

A problem caused by not doing so in Chrome has been reported [here](https://randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/amp/).

`File::sync_all()` calls `FlushFileBuffers()` down the line, causing potentially unflushed buffers on high I/O-load systems to flush and preventing nasty non-reproducible bugs.

Closes rust-lang#48545
  • Loading branch information
kennytm committed Apr 5, 2018
2 parents a70f844 + e1d3c47 commit 19c6908
Showing 1 changed file with 38 additions and 4 deletions.
42 changes: 38 additions & 4 deletions src/librustc_trans/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,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 @@ -822,7 +822,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 @@ -836,7 +836,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 @@ -870,7 +874,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

0 comments on commit 19c6908

Please sign in to comment.