Skip to content

Commit 19c6908

Browse files
authored
Rollup merge of rust-lang#49432 - nabijaczleweli:master, r=michaelwoerister
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
2 parents a70f844 + e1d3c47 commit 19c6908

File tree

1 file changed

+38
-4
lines changed

1 file changed

+38
-4
lines changed

src/librustc_trans/back/link.rs

+38-4
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ fn link_natively(sess: &Session,
694694
loop {
695695
i += 1;
696696
prog = time(sess, "running linker", || {
697-
exec_linker(sess, &mut cmd, tmpdir)
697+
exec_linker(sess, &mut cmd, out_filename, tmpdir)
698698
});
699699
let output = match prog {
700700
Ok(ref output) => output,
@@ -822,7 +822,7 @@ fn link_natively(sess: &Session,
822822
}
823823
}
824824

825-
fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path)
825+
fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: &Path)
826826
-> io::Result<Output>
827827
{
828828
// When attempting to spawn the linker we run a risk of blowing out the
@@ -836,7 +836,11 @@ fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path)
836836
// there instead of looking at the command line.
837837
if !cmd.very_likely_to_exceed_some_spawn_limit() {
838838
match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
839-
Ok(child) => return child.wait_with_output(),
839+
Ok(child) => {
840+
let output = child.wait_with_output();
841+
flush_linked_file(&output, out_filename)?;
842+
return output;
843+
}
840844
Err(ref e) if command_line_too_big(e) => {
841845
info!("command line to linker was too big: {}", e);
842846
}
@@ -870,7 +874,37 @@ fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path)
870874
fs::write(&file, &bytes)?;
871875
cmd2.arg(format!("@{}", file.display()));
872876
info!("invoking linker {:?}", cmd2);
873-
return cmd2.output();
877+
let output = cmd2.output();
878+
flush_linked_file(&output, out_filename)?;
879+
return output;
880+
881+
#[cfg(unix)]
882+
fn flush_linked_file(_: &io::Result<Output>, _: &Path) -> io::Result<()> {
883+
Ok(())
884+
}
885+
886+
#[cfg(windows)]
887+
fn flush_linked_file(command_output: &io::Result<Output>, out_filename: &Path)
888+
-> io::Result<()>
889+
{
890+
// On Windows, under high I/O load, output buffers are sometimes not flushed,
891+
// even long after process exit, causing nasty, non-reproducible output bugs.
892+
//
893+
// File::sync_all() calls FlushFileBuffers() down the line, which solves the problem.
894+
//
895+
// А full writeup of the original Chrome bug can be found at
896+
// randomascii.wordpress.com/2018/02/25/compiler-bug-linker-bug-windows-kernel-bug/amp
897+
898+
if let &Ok(ref out) = command_output {
899+
if out.status.success() {
900+
if let Ok(of) = fs::OpenOptions::new().write(true).open(out_filename) {
901+
of.sync_all()?;
902+
}
903+
}
904+
}
905+
906+
Ok(())
907+
}
874908

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

0 commit comments

Comments
 (0)