about summary refs log tree commit diff
path: root/src/librustc_trans
diff options
context:
space:
mode:
authornabijaczleweli <nabijaczleweli@gmail.com>2018-03-27 23:09:35 +0200
committernabijaczleweli <nabijaczleweli@gmail.com>2018-03-29 16:47:06 +0200
commitcd09c2b2abf2c03b80d0d48c9828004ade64a8f8 (patch)
treea290abc315a36216eaeb4ef0ab3eea8babc0fe85 /src/librustc_trans
parent9c9424de51da41fd3d1077ac7810276f8dc746fa (diff)
downloadrust-cd09c2b2abf2c03b80d0d48c9828004ade64a8f8.tar.gz
rust-cd09c2b2abf2c03b80d0d48c9828004ade64a8f8.zip
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 prevent nasty non-reproducible bugs.

The force-flush is only done on Windows and if the linker exited successfully

Closes #48545
Diffstat (limited to 'src/librustc_trans')
-rw-r--r--src/librustc_trans/back/link.rs36
1 files changed, 33 insertions, 3 deletions
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 75ba83a7c62..33f6ce9975e 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -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,
@@ -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
@@ -867,7 +867,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::File::open(out_filename) {
+                    of.sync_all()?;
+                }
+            }
+        }
+
+        Ok(())
+    }
 
     #[cfg(unix)]
     fn command_line_too_big(err: &io::Error) -> bool {