11pub mod convert;
22
33use std:: cmp;
4+ use std:: iter;
45use std:: mem;
56use std:: num:: NonZeroUsize ;
67use std:: time:: Duration ;
@@ -735,6 +736,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
735736 } )
736737 }
737738
739+ /// Read a sequence of bytes until the first null terminator.
738740 fn read_c_str < ' a > ( & ' a self , ptr : Pointer < Option < Provenance > > ) -> InterpResult < ' tcx , & ' a [ u8 ] >
739741 where
740742 ' tcx : ' a ,
@@ -761,6 +763,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
761763 this. read_bytes_ptr_strip_provenance ( ptr, len)
762764 }
763765
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.
764790 fn read_wide_str ( & self , mut ptr : Pointer < Option < Provenance > > ) -> InterpResult < ' tcx , Vec < u16 > > {
765791 let this = self . eval_context_ref ( ) ;
766792 let size2 = Size :: from_bytes ( 2 ) ;
@@ -783,6 +809,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
783809 Ok ( wchars)
784810 }
785811
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+
786845 /// Check that the ABI is what we expect.
787846 fn check_abi < ' a > ( & self , abi : Abi , exp_abi : Abi ) -> InterpResult < ' a , ( ) > {
788847 if self . eval_context_ref ( ) . machine . enforce_abi && abi != exp_abi {
0 commit comments