|
1 | 1 | use std::mem;
|
2 |
| -use std::ffi::OsString; |
| 2 | +use std::ffi::{OsStr, OsString}; |
3 | 3 |
|
4 | 4 | use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
|
5 | 5 | use rustc::mir;
|
@@ -351,40 +351,58 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
351 | 351 | }
|
352 | 352 |
|
353 | 353 | fn read_os_string(&mut self, scalar: Scalar<Tag>) -> InterpResult<'tcx, OsString> {
|
354 |
| - let bytes = self.eval_context_mut().memory.read_c_str(scalar)?.to_vec(); |
355 |
| - if cfg!(unix) { |
356 |
| - Ok(std::os::unix::ffi::OsStringExt::from_vec(bytes)) |
357 |
| - } else { |
358 |
| - std::str::from_utf8(&bytes) |
359 |
| - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes).into()) |
360 |
| - .map(OsString::from) |
361 |
| - } |
| 354 | + let bytes = self.eval_context_mut().memory.read_c_str(scalar)?; |
| 355 | + Ok(bytes_to_os_str(bytes)?.into()) |
362 | 356 | }
|
363 | 357 |
|
364 |
| - fn write_os_string(&mut self, os_string: OsString, ptr: Pointer<Tag>, size: u64) -> InterpResult<'tcx> { |
365 |
| - let mut bytes = if cfg!(unix) { |
366 |
| - std::os::unix::ffi::OsStringExt::into_vec(os_string) |
367 |
| - } else { |
368 |
| - os_string |
369 |
| - .into_string() |
370 |
| - .map_err(|os_string| err_unsup_format!("{:?} is not a valid utf-8 string", os_string))? |
371 |
| - .into_bytes() |
372 |
| - }; |
| 358 | + fn write_os_str(&mut self, os_str: &OsStr, ptr: Pointer<Tag>, size: u64) -> InterpResult<'tcx> { |
| 359 | + let bytes = os_str_to_bytes(os_str)?; |
373 | 360 | // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
|
374 | 361 | // terminator to memory using the `ptr` pointer would cause an overflow.
|
375 | 362 | if (bytes.len() as u64) < size {
|
376 |
| - // We add a `/0` terminator |
377 |
| - bytes.push(0); |
378 | 363 | let this = self.eval_context_mut();
|
379 | 364 | let tcx = &{ this.tcx.tcx };
|
380 | 365 | // This is ok because the buffer was strictly larger than `bytes`, so after adding the
|
381 | 366 | // null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that
|
382 | 367 | // `bytes` actually fit inside tbe buffer.
|
383 | 368 | this.memory
|
384 | 369 | .get_mut(ptr.alloc_id)?
|
385 |
| - .write_bytes(tcx, ptr, &bytes) |
| 370 | + .write_bytes(tcx, ptr, &bytes)?; |
| 371 | + // We write the `/0` terminator |
| 372 | + let tail_ptr = ptr.offset(Size::from_bytes(bytes.len() as u64 + 1), this)?; |
| 373 | + this.memory |
| 374 | + .get_mut(ptr.alloc_id)? |
| 375 | + .write_bytes(tcx, tail_ptr, b"0") |
386 | 376 | } else {
|
387 | 377 | throw_unsup_format!("OsString is larger than destination")
|
388 | 378 | }
|
389 | 379 | }
|
390 | 380 | }
|
| 381 | + |
| 382 | +#[cfg(target_os = "unix")] |
| 383 | +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { |
| 384 | + Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) |
| 385 | +} |
| 386 | + |
| 387 | +#[cfg(target_os = "unix")] |
| 388 | +fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { |
| 389 | + std::os::unix::ffi::OsStringExt::into_bytes(os_str) |
| 390 | +} |
| 391 | + |
| 392 | +// On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the |
| 393 | +// intermediate transformation into strings. Which invalidates non-utf8 paths that are actually |
| 394 | +// valid. |
| 395 | +#[cfg(not(target_os = "unix"))] |
| 396 | +fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { |
| 397 | + os_str |
| 398 | + .to_str() |
| 399 | + .map(|s| s.as_bytes()) |
| 400 | + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) |
| 401 | +} |
| 402 | + |
| 403 | +#[cfg(not(target_os = "unix"))] |
| 404 | +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { |
| 405 | + let s = std::str::from_utf8(bytes) |
| 406 | + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; |
| 407 | + Ok(&OsStr::new(s)) |
| 408 | +} |
0 commit comments