1
1
pub mod convert;
2
2
3
3
use std:: cmp;
4
+ use std:: iter;
4
5
use std:: mem;
5
6
use std:: num:: NonZeroUsize ;
6
7
use std:: time:: Duration ;
@@ -107,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
107
108
/// Gets an instance for a path.
108
109
fn resolve_path ( & self , path : & [ & str ] ) -> ty:: Instance < ' tcx > {
109
110
self . try_resolve_path ( path)
110
- . unwrap_or_else ( || panic ! ( "failed to find required Rust item: {:?}" , path ) )
111
+ . unwrap_or_else ( || panic ! ( "failed to find required Rust item: {path :?}" ) )
111
112
}
112
113
113
114
/// Evaluates the scalar at the specified path. Returns Some(val)
@@ -505,7 +506,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
505
506
RejectOpWith :: WarningWithoutBacktrace => {
506
507
this. tcx
507
508
. sess
508
- . warn ( & format ! ( "{} was made to return an error due to isolation" , op_name ) ) ;
509
+ . warn ( format ! ( "{op_name } was made to return an error due to isolation" ) ) ;
509
510
Ok ( ( ) )
510
511
}
511
512
RejectOpWith :: Warning => {
@@ -735,6 +736,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
735
736
} )
736
737
}
737
738
739
+ /// Read a sequence of bytes until the first null terminator.
738
740
fn read_c_str < ' a > ( & ' a self , ptr : Pointer < Option < Provenance > > ) -> InterpResult < ' tcx , & ' a [ u8 ] >
739
741
where
740
742
' tcx : ' a ,
@@ -761,6 +763,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
761
763
this. read_bytes_ptr_strip_provenance ( ptr, len)
762
764
}
763
765
766
+ /// Helper function to write a sequence of bytes with an added null-terminator, which is what
767
+ /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying
768
+ /// to write if `size` is not large enough to fit the contents of `c_str` plus a null
769
+ /// terminator. It returns `Ok((true, length))` if the writing process was successful. The
770
+ /// string length returned does include the null terminator.
771
+ fn write_c_str (
772
+ & mut self ,
773
+ c_str : & [ u8 ] ,
774
+ ptr : Pointer < Option < Provenance > > ,
775
+ size : u64 ,
776
+ ) -> InterpResult < ' tcx , ( bool , u64 ) > {
777
+ // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
778
+ // terminator to memory using the `ptr` pointer would cause an out-of-bounds access.
779
+ let string_length = u64:: try_from ( c_str. len ( ) ) . unwrap ( ) ;
780
+ let string_length = string_length. checked_add ( 1 ) . unwrap ( ) ;
781
+ if size < string_length {
782
+ return Ok ( ( false , string_length) ) ;
783
+ }
784
+ self . eval_context_mut ( )
785
+ . write_bytes_ptr ( ptr, c_str. iter ( ) . copied ( ) . chain ( iter:: once ( 0u8 ) ) ) ?;
786
+ Ok ( ( true , string_length) )
787
+ }
788
+
789
+ /// Read a sequence of u16 until the first null terminator.
764
790
fn read_wide_str ( & self , mut ptr : Pointer < Option < Provenance > > ) -> InterpResult < ' tcx , Vec < u16 > > {
765
791
let this = self . eval_context_ref ( ) ;
766
792
let size2 = Size :: from_bytes ( 2 ) ;
@@ -783,6 +809,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
783
809
Ok ( wchars)
784
810
}
785
811
812
+ /// Helper function to write a sequence of u16 with an added 0x0000-terminator, which is what
813
+ /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying
814
+ /// to write if `size` is not large enough to fit the contents of `os_string` plus a null
815
+ /// terminator. It returns `Ok((true, length))` if the writing process was successful. The
816
+ /// string length returned does include the null terminator. Length is measured in units of
817
+ /// `u16.`
818
+ fn write_wide_str (
819
+ & mut self ,
820
+ wide_str : & [ u16 ] ,
821
+ ptr : Pointer < Option < Provenance > > ,
822
+ size : u64 ,
823
+ ) -> InterpResult < ' tcx , ( bool , u64 ) > {
824
+ // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required
825
+ // 0x0000 terminator to memory would cause an out-of-bounds access.
826
+ let string_length = u64:: try_from ( wide_str. len ( ) ) . unwrap ( ) ;
827
+ let string_length = string_length. checked_add ( 1 ) . unwrap ( ) ;
828
+ if size < string_length {
829
+ return Ok ( ( false , string_length) ) ;
830
+ }
831
+
832
+ // Store the UTF-16 string.
833
+ let size2 = Size :: from_bytes ( 2 ) ;
834
+ let this = self . eval_context_mut ( ) ;
835
+ let mut alloc = this
836
+ . get_ptr_alloc_mut ( ptr, size2 * string_length, Align :: from_bytes ( 2 ) . unwrap ( ) ) ?
837
+ . unwrap ( ) ; // not a ZST, so we will get a result
838
+ for ( offset, wchar) in wide_str. iter ( ) . copied ( ) . chain ( iter:: once ( 0x0000 ) ) . enumerate ( ) {
839
+ let offset = u64:: try_from ( offset) . unwrap ( ) ;
840
+ alloc. write_scalar ( alloc_range ( size2 * offset, size2) , Scalar :: from_u16 ( wchar) ) ?;
841
+ }
842
+ Ok ( ( true , string_length) )
843
+ }
844
+
786
845
/// Check that the ABI is what we expect.
787
846
fn check_abi < ' a > ( & self , abi : Abi , exp_abi : Abi ) -> InterpResult < ' a , ( ) > {
788
847
if self . eval_context_ref ( ) . machine . enforce_abi && abi != exp_abi {
0 commit comments