Skip to content

Commit 4f171d7

Browse files
committed
stop relying on c_str/wide_str helpers in rustc
1 parent 516e905 commit 4f171d7

File tree

6 files changed

+83
-26
lines changed

6 files changed

+83
-26
lines changed

Diff for: src/helpers.rs

+45
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,51 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
566566
Duration::new(seconds, nanoseconds)
567567
})
568568
}
569+
570+
fn read_c_str<'a>(&'a self, sptr: Scalar<Tag>) -> InterpResult<'tcx, &'a [u8]>
571+
where
572+
'tcx: 'a,
573+
'mir: 'a,
574+
{
575+
let this = self.eval_context_ref();
576+
let size1 = Size::from_bytes(1);
577+
let ptr = this.force_ptr(sptr)?; // We need to read at least 1 byte, so we can eagerly get a ptr.
578+
579+
// Step 1: determine the length.
580+
let alloc = this.memory.get_raw(ptr.alloc_id)?;
581+
let mut len = Size::ZERO;
582+
loop {
583+
let byte = alloc.read_scalar(this, ptr.offset(len, this)?, size1)?.to_u8()?;
584+
if byte == 0 {
585+
break;
586+
} else {
587+
len = len + size1;
588+
}
589+
}
590+
591+
// Step 2: get the bytes.
592+
this.memory.read_bytes(ptr.into(), len)
593+
}
594+
595+
fn read_wide_str(&self, sptr: Scalar<Tag>) -> InterpResult<'tcx, Vec<u16>> {
596+
let this = self.eval_context_ref();
597+
let size2 = Size::from_bytes(2);
598+
599+
let mut ptr = this.force_ptr(sptr)?; // We need to read at least 1 wchar, so we can eagerly get a ptr.
600+
let mut wchars = Vec::new();
601+
let alloc = this.memory.get_raw(ptr.alloc_id)?;
602+
loop {
603+
let wchar = alloc.read_scalar(this, ptr, size2)?.to_u16()?;
604+
if wchar == 0 {
605+
break;
606+
} else {
607+
wchars.push(wchar);
608+
ptr = ptr.offset(size2, this)?;
609+
}
610+
}
611+
612+
Ok(wchars)
613+
}
569614
}
570615

571616
/// Check that the number of args is what we expect.

Diff for: src/shims/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
405405
check_abi(abi, Abi::C { unwind: false })?;
406406
let &[ref ptr] = check_arg_count(args)?;
407407
let ptr = this.read_scalar(ptr)?.check_init()?;
408-
let n = this.memory.read_c_str(ptr)?.len();
408+
let n = this.read_c_str(ptr)?.len();
409409
this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?;
410410
}
411411

Diff for: src/shims/os_str.rs

+33-21
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt};
99
#[cfg(windows)]
1010
use std::os::windows::ffi::{OsStrExt, OsStringExt};
1111

12-
use rustc_target::abi::LayoutOf;
12+
use rustc_target::abi::{LayoutOf, Size};
1313

1414
use crate::*;
1515

@@ -50,19 +50,19 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
5050
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
5151
/// Helper function to read an OsString from a null-terminated sequence of bytes, which is what
5252
/// the Unix APIs usually handle.
53-
fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar<Tag>) -> InterpResult<'tcx, &'a OsStr>
53+
fn read_os_str_from_c_str<'a>(&'a self, sptr: Scalar<Tag>) -> InterpResult<'tcx, &'a OsStr>
5454
where
5555
'tcx: 'a,
5656
'mir: 'a,
5757
{
5858
let this = self.eval_context_ref();
59-
let bytes = this.memory.read_c_str(scalar)?;
59+
let bytes = this.read_c_str(sptr)?;
6060
bytes_to_os_str(bytes)
6161
}
6262

6363
/// Helper function to read an OsString from a 0x0000-terminated sequence of u16,
6464
/// which is what the Windows APIs usually handle.
65-
fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar<Tag>) -> InterpResult<'tcx, OsString>
65+
fn read_os_str_from_wide_str<'a>(&'a self, sptr: Scalar<Tag>) -> InterpResult<'tcx, OsString>
6666
where
6767
'tcx: 'a,
6868
'mir: 'a,
@@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
7878
Ok(s.into())
7979
}
8080

81-
let u16_vec = self.eval_context_ref().memory.read_wide_str(scalar)?;
81+
let u16_vec = self.eval_context_ref().read_wide_str(sptr)?;
8282
u16vec_to_osstring(u16_vec)
8383
}
8484

@@ -90,7 +90,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
9090
fn write_os_str_to_c_str(
9191
&mut self,
9292
os_str: &OsStr,
93-
scalar: Scalar<Tag>,
93+
sptr: Scalar<Tag>,
9494
size: u64,
9595
) -> InterpResult<'tcx, (bool, u64)> {
9696
let bytes = os_str_to_bytes(os_str)?;
@@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
102102
}
103103
self.eval_context_mut()
104104
.memory
105-
.write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?;
105+
.write_bytes(sptr, bytes.iter().copied().chain(iter::once(0u8)))?;
106106
Ok((true, string_length))
107107
}
108108

@@ -114,7 +114,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
114114
fn write_os_str_to_wide_str(
115115
&mut self,
116116
os_str: &OsStr,
117-
scalar: Scalar<Tag>,
117+
sptr: Scalar<Tag>,
118118
size: u64,
119119
) -> InterpResult<'tcx, (bool, u64)> {
120120
#[cfg(windows)]
@@ -136,15 +136,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
136136
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required
137137
// 0x0000 terminator to memory would cause an out-of-bounds access.
138138
let string_length = u64::try_from(u16_vec.len()).unwrap();
139-
if size <= string_length {
139+
let string_length = string_length.checked_add(1).unwrap();
140+
if size < string_length {
140141
return Ok((false, string_length));
141142
}
142143

143144
// Store the UTF-16 string.
144-
self.eval_context_mut()
145-
.memory
146-
.write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?;
147-
Ok((true, string_length))
145+
let size2 = Size::from_bytes(2);
146+
let this = self.eval_context_mut();
147+
let tcx = &*this.tcx;
148+
let ptr = this.force_ptr(sptr)?; // we need to write at least the 0 terminator
149+
let alloc = this.memory.get_raw_mut(ptr.alloc_id)?;
150+
for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() {
151+
let offset = u64::try_from(offset).unwrap();
152+
alloc.write_scalar(
153+
tcx,
154+
ptr.offset(size2 * offset, tcx)?,
155+
Scalar::from_u16(wchar).into(),
156+
size2,
157+
)?;
158+
}
159+
Ok((true, string_length - 1))
148160
}
149161

150162
/// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.
@@ -178,13 +190,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
178190
}
179191

180192
/// Read a null-terminated sequence of bytes, and perform path separator conversion if needed.
181-
fn read_path_from_c_str<'a>(&'a self, scalar: Scalar<Tag>) -> InterpResult<'tcx, Cow<'a, Path>>
193+
fn read_path_from_c_str<'a>(&'a self, sptr: Scalar<Tag>) -> InterpResult<'tcx, Cow<'a, Path>>
182194
where
183195
'tcx: 'a,
184196
'mir: 'a,
185197
{
186198
let this = self.eval_context_ref();
187-
let os_str = this.read_os_str_from_c_str(scalar)?;
199+
let os_str = this.read_os_str_from_c_str(sptr)?;
188200

189201
Ok(match this.convert_path_separator(Cow::Borrowed(os_str), PathConversion::TargetToHost) {
190202
Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)),
@@ -193,9 +205,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
193205
}
194206

195207
/// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed.
196-
fn read_path_from_wide_str(&self, scalar: Scalar<Tag>) -> InterpResult<'tcx, PathBuf> {
208+
fn read_path_from_wide_str(&self, sptr: Scalar<Tag>) -> InterpResult<'tcx, PathBuf> {
197209
let this = self.eval_context_ref();
198-
let os_str = this.read_os_str_from_wide_str(scalar)?;
210+
let os_str = this.read_os_str_from_wide_str(sptr)?;
199211

200212
Ok(this
201213
.convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost)
@@ -208,27 +220,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
208220
fn write_path_to_c_str(
209221
&mut self,
210222
path: &Path,
211-
scalar: Scalar<Tag>,
223+
sptr: Scalar<Tag>,
212224
size: u64,
213225
) -> InterpResult<'tcx, (bool, u64)> {
214226
let this = self.eval_context_mut();
215227
let os_str = this
216228
.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
217-
this.write_os_str_to_c_str(&os_str, scalar, size)
229+
this.write_os_str_to_c_str(&os_str, sptr, size)
218230
}
219231

220232
/// Write a Path to the machine memory (as a null-terminated sequence of `u16`s),
221233
/// adjusting path separators if needed.
222234
fn write_path_to_wide_str(
223235
&mut self,
224236
path: &Path,
225-
scalar: Scalar<Tag>,
237+
sptr: Scalar<Tag>,
226238
size: u64,
227239
) -> InterpResult<'tcx, (bool, u64)> {
228240
let this = self.eval_context_mut();
229241
let os_str = this
230242
.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
231-
this.write_os_str_to_wide_str(&os_str, scalar, size)
243+
this.write_os_str_to_wide_str(&os_str, sptr, size)
232244
}
233245

234246
fn convert_path_separator<'a>(

Diff for: src/shims/posix/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
187187
let &[ref handle, ref symbol] = check_arg_count(args)?;
188188
this.read_scalar(handle)?.to_machine_usize(this)?;
189189
let symbol = this.read_scalar(symbol)?.check_init()?;
190-
let symbol_name = this.memory.read_c_str(symbol)?;
190+
let symbol_name = this.read_c_str(symbol)?;
191191
if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? {
192192
let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
193193
this.write_scalar(Scalar::from(ptr), dest)?;

Diff for: src/shims/posix/thread.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
111111
let option = this.read_scalar(option)?.to_i32()?;
112112
if option == this.eval_libc_i32("PR_SET_NAME")? {
113113
let address = this.read_scalar(arg2)?.check_init()?;
114-
let mut name = this.memory.read_c_str(address)?.to_owned();
114+
let mut name = this.read_c_str(address)?.to_owned();
115115
// The name should be no more than 16 bytes, including the null
116116
// byte. Since `read_c_str` returns the string without the null
117117
// byte, we need to truncate to 15.
@@ -134,7 +134,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
134134
let this = self.eval_context_mut();
135135
this.assert_target_os("macos", "pthread_setname_np");
136136

137-
let name = this.memory.read_c_str(name)?.to_owned();
137+
let name = this.read_c_str(name)?.to_owned();
138138
this.set_active_thread_name(name);
139139

140140
Ok(())

Diff for: src/shims/windows/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
271271
#[allow(non_snake_case)]
272272
let &[ref hModule, ref lpProcName] = check_arg_count(args)?;
273273
this.read_scalar(hModule)?.to_machine_isize(this)?;
274-
let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?;
274+
let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?;
275275
if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? {
276276
let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
277277
this.write_scalar(Scalar::from(ptr), dest)?;

0 commit comments

Comments
 (0)