@@ -51,7 +51,7 @@ enum MiriCommand {
51
51
}
52
52
53
53
/// The information to run a crate with the given environment.
54
- #[ derive( Serialize , Deserialize ) ]
54
+ #[ derive( Clone , Serialize , Deserialize ) ]
55
55
struct CrateRunEnv {
56
56
/// The command-line arguments.
57
57
args : Vec < String > ,
@@ -251,26 +251,72 @@ fn xargo_check() -> Command {
251
251
252
252
/// Execute the command. If it fails, fail this process with the same exit code.
253
253
/// Otherwise, continue.
254
- fn exec ( mut cmd : Command ) {
255
- let exit_status = cmd. status ( ) . expect ( "failed to run command" ) ;
256
- if exit_status. success ( ) . not ( ) {
257
- std:: process:: exit ( exit_status. code ( ) . unwrap_or ( -1 ) )
254
+ fn exec ( mut cmd : Command ) -> ! {
255
+ // On non-Unix imitate POSIX exec as closely as we can
256
+ #[ cfg( not( unix) ) ]
257
+ {
258
+ let exit_status = cmd. status ( ) . expect ( "failed to run command" ) ;
259
+ std:: process:: exit ( exit_status. code ( ) . unwrap_or ( -1 ) ) ;
260
+ }
261
+ // On Unix targets, actually exec
262
+ // If exec returns, process setup has failed. This is the same error condition as the expect in
263
+ // the non-Unix case.
264
+ #[ cfg( unix) ]
265
+ {
266
+ use std:: os:: unix:: process:: CommandExt ;
267
+ let error = cmd. exec ( ) ;
268
+ Err ( error) . expect ( "failed to run command" )
258
269
}
259
270
}
260
271
261
272
/// Execute the command and pipe `input` into its stdin.
262
273
/// If it fails, fail this process with the same exit code.
263
274
/// Otherwise, continue.
264
275
fn exec_with_pipe ( mut cmd : Command , input : & [ u8 ] ) {
265
- cmd. stdin ( process:: Stdio :: piped ( ) ) ;
266
- let mut child = cmd. spawn ( ) . expect ( "failed to spawn process" ) ;
276
+ #[ cfg( unix) ]
267
277
{
268
- let stdin = child. stdin . as_mut ( ) . expect ( "failed to open stdin" ) ;
269
- stdin. write_all ( input) . expect ( "failed to write out test source" ) ;
278
+ use std:: os:: unix:: io:: FromRawFd ;
279
+ use std:: process:: Stdio ;
280
+
281
+ let mut fds: [ libc:: c_int ; 2 ] = [ 0 , 0 ] ;
282
+ // SAFETY: fds is an array of 2 libc::c_int
283
+ let res = unsafe { libc:: pipe ( fds. as_mut_ptr ( ) ) } ;
284
+ assert_eq ! ( res, 0 , "failed to create pipe" ) ;
285
+
286
+ // We need to set close-on-exec, otherwise our pipe isn't readable after exec
287
+ // SAFETY: fcntl has no preconditions
288
+ unsafe {
289
+ for fd in & fds {
290
+ let res = libc:: fcntl (
291
+ * fd,
292
+ libc:: F_SETFD ,
293
+ libc:: fcntl ( * fd, libc:: F_GETFD ) | libc:: FD_CLOEXEC ,
294
+ ) ;
295
+ assert_eq ! ( res, 0 , "failed to set close-on-exec for pipe" ) ;
296
+ }
297
+ }
298
+
299
+ // SAFETY: Both elements of fds are open file descriptors, because pipe2 returned 0
300
+ let dst = unsafe { Stdio :: from_raw_fd ( fds[ 0 ] ) } ;
301
+ let mut src = unsafe { File :: from_raw_fd ( fds[ 1 ] ) } ;
302
+
303
+ src. write_all ( input) . expect ( "failed to write out test source" ) ;
304
+
305
+ cmd. stdin ( dst) ;
306
+ exec ( cmd)
270
307
}
271
- let exit_status = child. wait ( ) . expect ( "failed to run command" ) ;
272
- if exit_status. success ( ) . not ( ) {
273
- std:: process:: exit ( exit_status. code ( ) . unwrap_or ( -1 ) )
308
+ #[ cfg( not( unix) ) ]
309
+ {
310
+ cmd. stdin ( process:: Stdio :: piped ( ) ) ;
311
+ let mut child = cmd. spawn ( ) . expect ( "failed to spawn process" ) ;
312
+ {
313
+ let stdin = child. stdin . as_mut ( ) . expect ( "failed to open stdin" ) ;
314
+ stdin. write_all ( input) . expect ( "failed to write out test source" ) ;
315
+ }
316
+ let exit_status = child. wait ( ) . expect ( "failed to run command" ) ;
317
+ if exit_status. success ( ) . not ( ) {
318
+ std:: process:: exit ( exit_status. code ( ) . unwrap_or ( -1 ) )
319
+ }
274
320
}
275
321
}
276
322
@@ -872,6 +918,8 @@ fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
872
918
// and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase.
873
919
let env = CrateRunEnv :: collect ( args, inside_rustdoc) ;
874
920
921
+ store_json ( CrateRunInfo :: RunWith ( env. clone ( ) ) ) ;
922
+
875
923
// Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`,
876
924
// just creating the JSON file is not enough: we need to detect syntax errors,
877
925
// so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build.
@@ -888,7 +936,14 @@ fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
888
936
cmd. arg ( "--emit=metadata" ) ;
889
937
}
890
938
891
- cmd. args ( & env. args ) ;
939
+ let mut args = env. args . clone ( ) ;
940
+ for i in 0 ..args. len ( ) {
941
+ if args[ i] == "-o" {
942
+ args[ i + 1 ] = format ! ( "{}_miri" , args[ i + 1 ] ) ;
943
+ }
944
+ }
945
+
946
+ cmd. args ( & args) ;
892
947
cmd. env ( "MIRI_BE_RUSTC" , "target" ) ;
893
948
894
949
if verbose > 0 {
@@ -902,8 +957,6 @@ fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
902
957
exec_with_pipe ( cmd, & env. stdin ) ;
903
958
}
904
959
905
- store_json ( CrateRunInfo :: RunWith ( env) ) ;
906
-
907
960
return ;
908
961
}
909
962
@@ -983,8 +1036,6 @@ fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
983
1036
"[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} print={print}"
984
1037
) ;
985
1038
}
986
- debug_cmd ( "[cargo-miri rustc]" , verbose, & cmd) ;
987
- exec ( cmd) ;
988
1039
989
1040
// Create a stub .rlib file if "link" was requested by cargo.
990
1041
// This is necessary to prevent cargo from doing rebuilds all the time.
@@ -999,6 +1050,9 @@ fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
999
1050
File :: create ( out_filename ( "" , ".dll" ) ) . expect ( "failed to create fake .dll file" ) ;
1000
1051
File :: create ( out_filename ( "" , ".lib" ) ) . expect ( "failed to create fake .lib file" ) ;
1001
1052
}
1053
+
1054
+ debug_cmd ( "[cargo-miri rustc]" , verbose, & cmd) ;
1055
+ exec ( cmd) ;
1002
1056
}
1003
1057
1004
1058
#[ derive( Debug , Copy , Clone , PartialEq ) ]
0 commit comments