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