@@ -4,7 +4,7 @@ use core::{
44 cell:: SyncUnsafeCell ,
55 cmp:: { self , Ordering } ,
66 fmt:: { self , Display , Write } ,
7- iter:: { Step , repeat_with} ,
7+ iter:: repeat_with,
88 mem:: { MaybeUninit , needs_drop} ,
99 num:: { NonZeroU32 , NonZeroUsize } ,
1010 ops:: { Bound , Range , RangeBounds } ,
@@ -280,21 +280,52 @@ impl VirtualMemory {
280280 }
281281
282282 /// Read a string from userspace.
283- pub fn read_cstring ( & self , pointer : Pointer < CString > , max_length : usize ) -> Result < CString > {
284- let mut addr = pointer . get ( ) ;
285- let mut ret = Vec :: new ( ) ;
283+ pub fn read_cstring ( & self , pointer : Pointer < CString > , max_len : usize ) -> Result < CString > {
284+ let mut buf = Vec :: new ( ) ;
285+
286286 loop {
287- let mut buf = 0 ;
288- self . read_bytes ( addr, core:: array:: from_mut ( & mut buf) ) ?;
289- if buf == 0 {
290- break ;
287+ // Make sure that the string doesn't exceed the maximum length.
288+ ensure ! ( buf. len( ) < max_len, NameTooLong ) ;
289+
290+ // Allocate some more memory.
291+ buf. reserve ( 1 ) ;
292+ let ( init, uninit) = buf. split_at_spare_mut ( ) ;
293+
294+ // Determine how many bytes to read. Reads are limited by the following:
295+ // - the remaining capacity
296+ // - the maximum (remaining) string length
297+ // - the end of the page
298+ let current_len = init. len ( ) ;
299+ let addr = pointer. get ( ) + u64:: from_usize ( current_len) ;
300+ let page_offset = u16:: from ( addr. page_offset ( ) ) ;
301+ let remaining_len_in_page =
302+ usize:: from ( ( page_offset + 1 ) . next_multiple_of ( 0x1000 ) - page_offset) ;
303+ let read_len = cmp:: min ( uninit. len ( ) , max_len - current_len) ;
304+ let read_len = cmp:: min ( read_len, remaining_len_in_page) ;
305+ debug_assert_ne ! ( read_len, 0 ) ;
306+
307+ // Read more string bytes.
308+ let bytes = self . read_uninit_bytes ( addr, & mut uninit[ ..read_len] ) ?;
309+
310+ // Look for a null-byte in the newly read bytes.
311+ let idx = bytes. iter ( ) . position ( |& b| b == 0 ) ;
312+
313+ // Update the buffer length.
314+ let new_len = current_len + read_len;
315+ unsafe {
316+ buf. set_len ( new_len) ;
317+ }
318+
319+ // If there was a null-byte, then we're done.
320+ if let Some ( idx) = idx {
321+ // Truncate the string just after the null-byte.
322+ let cstring_len = current_len + idx + 1 ;
323+ buf. truncate ( cstring_len) ;
324+
325+ let cstr = unsafe { CString :: from_vec_with_nul_unchecked ( buf) } ;
326+ return Ok ( cstr) ;
291327 }
292- ensure ! ( ret. len( ) < max_length, NameTooLong ) ;
293- addr = Step :: forward ( addr, 1 ) ;
294- ret. push ( buf) ;
295328 }
296- let ret = CString :: new ( ret) . unwrap ( ) ;
297- Ok ( ret)
298329 }
299330
300331 pub fn set_bytes ( & self , addr : VirtAddr , count : usize , byte : u8 ) -> Result < ( ) > {
0 commit comments