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