about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-04-05 16:51:20 +0800
committerGitHub <noreply@github.com>2018-04-05 16:51:20 +0800
commit19c69082f5b0e5b44fe660b6bdd73ea8ac60b6b0 (patch)
tree60c656c9b362e0d82b711507c2c551abf77dfefa
parenta70f84401286b58c5767ada0dfd63729640af0e9 (diff)
parente1d3c471d75bbc4360eee17178ccb32dce348542 (diff)
downloadrust-19c69082f5b0e5b44fe660b6bdd73ea8ac60b6b0.tar.gz
rust-19c69082f5b0e5b44fe660b6bdd73ea8ac60b6b0.zip
Rollup merge of #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 #48545
-rw-r--r--src/librustc_trans/back/link.rs42
1 files changed, 38 insertions, 4 deletions
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 6ba3ad879b7..4ffc71ba470 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -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,
@@ -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
@@ -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);
             }
@@ -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 {