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
This commit is contained in:
kennytm 2018-04-05 16:51:20 +08:00 committed by GitHub
commit 19c69082f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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 {