@@ -4,6 +4,7 @@ use rustc_span::Symbol;
4
4
use rustc_target:: abi:: Size ;
5
5
use rustc_target:: spec:: abi:: Abi ;
6
6
7
+ use crate :: helpers:: check_arg_count;
7
8
use crate :: * ;
8
9
use shims:: foreign_items:: EmulateByNameResult ;
9
10
use shims:: windows:: handle:: { EvalContextExt as _, Handle , PseudoHandle } ;
@@ -453,10 +454,70 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
453
454
// FIXME: this should return a nonzero value if this call does result in switching to another thread.
454
455
this. write_null ( dest) ?;
455
456
}
457
+ "NtWriteFile" if this. frame_in_std ( ) => {
458
+ this. check_abi_and_shim_symbol_clash (
459
+ abi,
460
+ Abi :: System { unwind : false } ,
461
+ link_name,
462
+ ) ?;
463
+ nt_write_file ( this, args, dest) ?;
464
+ }
456
465
457
466
_ => return Ok ( EmulateByNameResult :: NotSupported ) ,
458
467
}
459
468
460
469
Ok ( EmulateByNameResult :: NeedsJumping )
461
470
}
462
471
}
472
+
473
+ // Incomplete implementation of `NtWriteFile`.
474
+ pub ( super ) fn nt_write_file < ' a , ' mir , ' tcx > (
475
+ this : & ' a mut MiriInterpCx < ' mir , ' tcx > ,
476
+ args : & [ OpTy < ' tcx , Provenance > ] ,
477
+ dest : & PlaceTy < ' tcx , Provenance > ,
478
+ ) -> InterpResult < ' tcx , ( ) > {
479
+ let [ handle, _event, _apc_routine, _apc_context, io_status_block, buf, n, byte_offset, _key] =
480
+ check_arg_count ( args) ?;
481
+
482
+ let handle = this. read_scalar ( handle) ?. to_machine_isize ( this) ?;
483
+ let buf = this. read_pointer ( buf) ?;
484
+ let n = this. read_scalar ( n) ?. to_u32 ( ) ?;
485
+ let byte_offset = this. read_scalar ( byte_offset) ?. to_machine_usize ( this) ?; // is actually a pointer
486
+ let io_status_block = this. deref_operand ( io_status_block) ?;
487
+
488
+ if byte_offset != 0 {
489
+ throw_unsup_format ! (
490
+ "`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported"
491
+ ) ;
492
+ }
493
+
494
+ let written = if handle == -11 || handle == -12 {
495
+ // stdout/stderr
496
+ use std:: io:: { self , Write } ;
497
+
498
+ let buf_cont = this. read_bytes_ptr_strip_provenance ( buf, Size :: from_bytes ( u64:: from ( n) ) ) ?;
499
+ let res = if this. machine . mute_stdout_stderr {
500
+ Ok ( buf_cont. len ( ) )
501
+ } else if handle == -11 {
502
+ io:: stdout ( ) . write ( buf_cont)
503
+ } else {
504
+ io:: stderr ( ) . write ( buf_cont)
505
+ } ;
506
+ // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that.
507
+ res. ok ( ) . map ( |n| u32:: try_from ( n) . unwrap ( ) )
508
+ } else {
509
+ throw_unsup_format ! ( "on Windows, writing to anything except stdout/stderr is not supported" )
510
+ } ;
511
+ // We have to put the result into io_status_block.
512
+ if let Some ( n) = written {
513
+ let io_status_information = this. mplace_field_named ( & io_status_block, "Information" ) ?;
514
+ this. write_scalar (
515
+ Scalar :: from_machine_usize ( n. into ( ) , this) ,
516
+ & io_status_information. into ( ) ,
517
+ ) ?;
518
+ }
519
+ // Return whether this was a success. >= 0 is success.
520
+ // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
521
+ this. write_scalar ( Scalar :: from_u32 ( if written. is_some ( ) { 0 } else { 0xC0000185u32 } ) , dest) ?;
522
+ Ok ( ( ) )
523
+ }
0 commit comments