@@ -982,29 +982,46 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
982982 Ok ( ( true , string_length) )
983983 }
984984
985- /// Read a sequence of u16 until the first null terminator.
986- fn read_wide_str ( & self , mut ptr : Pointer < Option < Provenance > > ) -> InterpResult < ' tcx , Vec < u16 > > {
985+ /// Helper function to read a sequence of unsigned integers of the given size and alignment
986+ /// until the first null terminator.
987+ fn read_c_str_with_char_size < T > (
988+ & self ,
989+ mut ptr : Pointer < Option < Provenance > > ,
990+ size : Size ,
991+ align : Align ,
992+ ) -> InterpResult < ' tcx , Vec < T > >
993+ where
994+ T : TryFrom < u128 > ,
995+ <T as TryFrom < u128 > >:: Error : std:: fmt:: Debug ,
996+ {
997+ assert_ne ! ( size, Size :: ZERO ) ;
998+
987999 let this = self . eval_context_ref ( ) ;
988- let size2 = Size :: from_bytes ( 2 ) ;
989- this. check_ptr_align ( ptr, Align :: from_bytes ( 2 ) . unwrap ( ) ) ?;
1000+
1001+ this. check_ptr_align ( ptr, align ) ?;
9901002
9911003 let mut wchars = Vec :: new ( ) ;
9921004 loop {
9931005 // FIXME: We are re-getting the allocation each time around the loop.
9941006 // Would be nice if we could somehow "extend" an existing AllocRange.
995- let alloc = this. get_ptr_alloc ( ptr, size2 ) ?. unwrap ( ) ; // not a ZST, so we will get a result
996- let wchar = alloc. read_integer ( alloc_range ( Size :: ZERO , size2 ) ) ?. to_u16 ( ) ?;
997- if wchar == 0 {
1007+ let alloc = this. get_ptr_alloc ( ptr, size ) ?. unwrap ( ) ; // not a ZST, so we will get a result
1008+ let wchar_int = alloc. read_integer ( alloc_range ( Size :: ZERO , size ) ) ?. to_bits ( size ) ?;
1009+ if wchar_int == 0 {
9981010 break ;
9991011 } else {
1000- wchars. push ( wchar ) ;
1001- ptr = ptr. offset ( size2 , this) ?;
1012+ wchars. push ( wchar_int . try_into ( ) . unwrap ( ) ) ;
1013+ ptr = ptr. offset ( size , this) ?;
10021014 }
10031015 }
10041016
10051017 Ok ( wchars)
10061018 }
10071019
1020+ /// Read a sequence of u16 until the first null terminator.
1021+ fn read_wide_str ( & self , ptr : Pointer < Option < Provenance > > ) -> InterpResult < ' tcx , Vec < u16 > > {
1022+ self . read_c_str_with_char_size ( ptr, Size :: from_bytes ( 2 ) , Align :: from_bytes ( 2 ) . unwrap ( ) )
1023+ }
1024+
10081025 /// Helper function to write a sequence of u16 with an added 0x0000-terminator, which is what
10091026 /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying
10101027 /// to write if `size` is not large enough to fit the contents of `os_string` plus a null
@@ -1037,6 +1054,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10371054 Ok ( ( true , string_length) )
10381055 }
10391056
1057+ /// Read a sequence of wchar_t until the first null terminator.
1058+ /// Always returns a `Vec<u32>` no matter the size of `wchar_t`.
1059+ fn read_wchar_t_str ( & self , ptr : Pointer < Option < Provenance > > ) -> InterpResult < ' tcx , Vec < u32 > > {
1060+ let this = self . eval_context_ref ( ) ;
1061+ let wchar_t = this. libc_ty_layout ( "wchar_t" ) ;
1062+ self . read_c_str_with_char_size ( ptr, wchar_t. size , wchar_t. align . abi )
1063+ }
1064+
10401065 /// Check that the ABI is what we expect.
10411066 fn check_abi < ' a > ( & self , abi : Abi , exp_abi : Abi ) -> InterpResult < ' a , ( ) > {
10421067 if abi != exp_abi {
0 commit comments