|
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<'a>(&mut self, os_str: &'a 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_mut() |
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_mut() |
| 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