Skip to content

Commit 7218df8

Browse files
committed
Use conditional compilation properly and work with OsStrs instead
1 parent 972c6d4 commit 7218df8

File tree

2 files changed

+41
-22
lines changed

2 files changed

+41
-22
lines changed

src/helpers.rs

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::mem;
2-
use std::ffi::OsString;
2+
use std::ffi::{OsStr, OsString};
33

44
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
55
use rustc::mir;
@@ -351,40 +351,58 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
351351
}
352352

353353
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())
362356
}
363357

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)?;
373360
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
374361
// terminator to memory using the `ptr` pointer would cause an overflow.
375362
if (bytes.len() as u64) < size {
376-
// We add a `/0` terminator
377-
bytes.push(0);
378363
let this = self.eval_context_mut();
379364
let tcx = &{ this.tcx.tcx };
380365
// This is ok because the buffer was strictly larger than `bytes`, so after adding the
381366
// null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that
382367
// `bytes` actually fit inside tbe buffer.
383368
this.memory
384369
.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")
386376
} else {
387377
throw_unsup_format!("OsString is larger than destination")
388378
}
389379
}
390380
}
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+
}

src/shims/env.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::collections::HashMap;
2+
use std::ffi::OsString;
23
use std::env;
34

45
use crate::stacked_borrows::Tag;
@@ -129,7 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
129130
// If we cannot get the current directory, we return null
130131
match env::current_dir() {
131132
Ok(cwd) => {
132-
if this.write_os_string(cwd.into(), buf, size).is_ok() {
133+
if this.write_os_str(&OsString::from(cwd), buf, size).is_ok() {
133134
return Ok(Scalar::Ptr(buf));
134135
}
135136
let erange = this.eval_libc("ERANGE")?;

0 commit comments

Comments
 (0)