Skip to content

Commit 68fec4b

Browse files
committed
Use conditional compilation properly and work with OsStrs instead
1 parent 1241abb commit 68fec4b

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;
@@ -347,40 +347,58 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
347347
}
348348

349349
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())
358352
}
359353

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)?;
369356
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
370357
// terminator to memory using the `ptr` pointer would cause an overflow.
371358
if (bytes.len() as u64) < size {
372-
// We add a `/0` terminator
373-
bytes.push(0);
374359
let this = self.eval_context_mut();
375360
let tcx = &{ this.tcx.tcx };
376361
// This is ok because the buffer was strictly larger than `bytes`, so after adding the
377362
// null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that
378363
// `bytes` actually fit inside tbe buffer.
379364
this.memory
380365
.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")
382372
} else {
383373
throw_unsup_format!("OsString is larger than destination")
384374
}
385375
}
386376
}
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+
}

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;
@@ -127,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
127128
// If we cannot get the current directory, we return null
128129
match env::current_dir() {
129130
Ok(cwd) => {
130-
if this.write_os_string(cwd.into(), buf, size).is_ok() {
131+
if this.write_os_str(&OsString::from(cwd), buf, size).is_ok() {
131132
return Ok(Scalar::Ptr(buf));
132133
}
133134
let erange = this.eval_libc("ERANGE")?;

0 commit comments

Comments
 (0)