3
3
use crate :: char:: decode_utf16;
4
4
use crate :: cmp;
5
5
use crate :: io;
6
+ use crate :: mem:: MaybeUninit ;
6
7
use crate :: os:: windows:: io:: { FromRawHandle , IntoRawHandle } ;
7
8
use crate :: ptr;
8
9
use crate :: str;
@@ -169,13 +170,14 @@ fn write(
169
170
}
170
171
171
172
fn write_valid_utf8_to_console ( handle : c:: HANDLE , utf8 : & str ) -> io:: Result < usize > {
172
- let mut utf16 = [ 0u16 ; MAX_BUFFER_SIZE / 2 ] ;
173
+ let mut utf16 = [ MaybeUninit :: < u16 > :: uninit ( ) ; MAX_BUFFER_SIZE / 2 ] ;
173
174
let mut len_utf16 = 0 ;
174
175
for ( chr, dest) in utf8. encode_utf16 ( ) . zip ( utf16. iter_mut ( ) ) {
175
- * dest = chr;
176
+ * dest = MaybeUninit :: new ( chr) ;
176
177
len_utf16 += 1 ;
177
178
}
178
- let utf16 = & utf16[ ..len_utf16] ;
179
+ // Safety: We've initialized `len_utf16` values.
180
+ let utf16: & [ u16 ] = unsafe { MaybeUninit :: slice_assume_init_ref ( & utf16[ ..len_utf16] ) } ;
179
181
180
182
let mut written = write_u16s ( handle, & utf16) ?;
181
183
@@ -250,27 +252,33 @@ impl io::Read for Stdin {
250
252
return Ok ( bytes_copied) ;
251
253
} else if buf. len ( ) - bytes_copied < 4 {
252
254
// Not enough space to get a UTF-8 byte. We will use the incomplete UTF8.
253
- let mut utf16_buf = [ 0u16 ; 1 ] ;
255
+ let mut utf16_buf = [ MaybeUninit :: new ( 0 ) ; 1 ] ;
254
256
// Read one u16 character.
255
257
let read = read_u16s_fixup_surrogates ( handle, & mut utf16_buf, 1 , & mut self . surrogate ) ?;
256
258
// Read bytes, using the (now-empty) self.incomplete_utf8 as extra space.
257
- let read_bytes = utf16_to_utf8 ( & utf16_buf[ ..read] , & mut self . incomplete_utf8 . bytes ) ?;
259
+ let read_bytes = utf16_to_utf8 (
260
+ unsafe { MaybeUninit :: slice_assume_init_ref ( & utf16_buf[ ..read] ) } ,
261
+ & mut self . incomplete_utf8 . bytes ,
262
+ ) ?;
258
263
259
264
// Read in the bytes from incomplete_utf8 until the buffer is full.
260
265
self . incomplete_utf8 . len = read_bytes as u8 ;
261
266
// No-op if no bytes.
262
267
bytes_copied += self . incomplete_utf8 . read ( & mut buf[ bytes_copied..] ) ;
263
268
Ok ( bytes_copied)
264
269
} else {
265
- let mut utf16_buf = [ 0u16 ; MAX_BUFFER_SIZE / 2 ] ;
270
+ let mut utf16_buf = [ MaybeUninit :: < u16 > :: uninit ( ) ; MAX_BUFFER_SIZE / 2 ] ;
271
+
266
272
// In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So
267
273
// we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets
268
274
// lost.
269
275
let amount = cmp:: min ( buf. len ( ) / 3 , utf16_buf. len ( ) ) ;
270
276
let read =
271
277
read_u16s_fixup_surrogates ( handle, & mut utf16_buf, amount, & mut self . surrogate ) ?;
272
-
273
- match utf16_to_utf8 ( & utf16_buf[ ..read] , buf) {
278
+ // Safety `read_u16s_fixup_surrogates` returns the number of items
279
+ // initialized.
280
+ let utf16s = unsafe { MaybeUninit :: slice_assume_init_ref ( & utf16_buf[ ..read] ) } ;
281
+ match utf16_to_utf8 ( utf16s, buf) {
274
282
Ok ( value) => return Ok ( bytes_copied + value) ,
275
283
Err ( e) => return Err ( e) ,
276
284
}
@@ -283,14 +291,14 @@ impl io::Read for Stdin {
283
291
// This is a best effort, and might not work if we are not the only reader on Stdin.
284
292
fn read_u16s_fixup_surrogates (
285
293
handle : c:: HANDLE ,
286
- buf : & mut [ u16 ] ,
294
+ buf : & mut [ MaybeUninit < u16 > ] ,
287
295
mut amount : usize ,
288
296
surrogate : & mut u16 ,
289
297
) -> io:: Result < usize > {
290
298
// Insert possibly remaining unpaired surrogate from last read.
291
299
let mut start = 0 ;
292
300
if * surrogate != 0 {
293
- buf[ 0 ] = * surrogate;
301
+ buf[ 0 ] = MaybeUninit :: new ( * surrogate) ;
294
302
* surrogate = 0 ;
295
303
start = 1 ;
296
304
if amount == 1 {
@@ -303,7 +311,10 @@ fn read_u16s_fixup_surrogates(
303
311
let mut amount = read_u16s ( handle, & mut buf[ start..amount] ) ? + start;
304
312
305
313
if amount > 0 {
306
- let last_char = buf[ amount - 1 ] ;
314
+ // Safety: The returned `amount` is the number of values initialized,
315
+ // and it is not 0, so we know that `buf[amount - 1]` have been
316
+ // initialized.
317
+ let last_char = unsafe { buf[ amount - 1 ] . assume_init ( ) } ;
307
318
if last_char >= 0xD800 && last_char <= 0xDBFF {
308
319
// high surrogate
309
320
* surrogate = last_char;
@@ -313,7 +324,8 @@ fn read_u16s_fixup_surrogates(
313
324
Ok ( amount)
314
325
}
315
326
316
- fn read_u16s ( handle : c:: HANDLE , buf : & mut [ u16 ] ) -> io:: Result < usize > {
327
+ // Returns `Ok(n)` if it initialized `n` values in `buf`.
328
+ fn read_u16s ( handle : c:: HANDLE , buf : & mut [ MaybeUninit < u16 > ] ) -> io:: Result < usize > {
317
329
// Configure the `pInputControl` parameter to not only return on `\r\n` but also Ctrl-Z, the
318
330
// traditional DOS method to indicate end of character stream / user input (SUB).
319
331
// See #38274 and https://stackoverflow.com/questions/43836040/win-api-readconsole.
@@ -346,8 +358,9 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [u16]) -> io::Result<usize> {
346
358
}
347
359
break ;
348
360
}
349
-
350
- if amount > 0 && buf[ amount as usize - 1 ] == CTRL_Z {
361
+ // Safety: if `amount > 0`, then that many bytes were written, so
362
+ // `buf[amount as usize - 1]` has been initialized.
363
+ if amount > 0 && unsafe { buf[ amount as usize - 1 ] . assume_init ( ) } == CTRL_Z {
351
364
amount -= 1 ;
352
365
}
353
366
Ok ( amount as usize )
0 commit comments