@@ -694,7 +694,7 @@ fn link_natively(sess: &Session,
694
694
loop {
695
695
i += 1 ;
696
696
prog = time ( sess, "running linker" , || {
697
- exec_linker ( sess, & mut cmd, tmpdir)
697
+ exec_linker ( sess, & mut cmd, out_filename , tmpdir)
698
698
} ) ;
699
699
let output = match prog {
700
700
Ok ( ref output) => output,
@@ -822,7 +822,7 @@ fn link_natively(sess: &Session,
822
822
}
823
823
}
824
824
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 )
826
826
-> io:: Result < Output >
827
827
{
828
828
// 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)
836
836
// there instead of looking at the command line.
837
837
if !cmd. very_likely_to_exceed_some_spawn_limit ( ) {
838
838
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
+ }
840
844
Err ( ref e) if command_line_too_big ( e) => {
841
845
info ! ( "command line to linker was too big: {}" , e) ;
842
846
}
@@ -870,7 +874,37 @@ fn exec_linker(sess: &Session, cmd: &mut Command, tmpdir: &Path)
870
874
fs:: write ( & file, & bytes) ?;
871
875
cmd2. arg ( format ! ( "@{}" , file. display( ) ) ) ;
872
876
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
+ }
874
908
875
909
#[ cfg( unix) ]
876
910
fn command_line_too_big ( err : & io:: Error ) -> bool {
0 commit comments