Skip to content

Commit f0cd098

Browse files
committed
Auto merge of #2470 - RalfJung:macos-env, r=RalfJung
support current_exe and home_dir on macOS also fix write_os_str length logic
2 parents f633537 + 79d147e commit f0cd098

20 files changed

+86
-46
lines changed

ci.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ case $HOST_TARGET in
8080
MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
8181
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
8282
MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
83-
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir data_race env
83+
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec data_race env/var
8484
MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture
8585
;;
8686
x86_64-apple-darwin)

src/shims/env.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 {
1818
if success {
1919
// If the function succeeds, the return value is the number of characters stored in the target buffer,
2020
// not including the terminating null character.
21-
u32::try_from(len).unwrap()
21+
u32::try_from(len.checked_sub(1).unwrap()).unwrap()
2222
} else {
2323
// If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters,
2424
// required to hold the string and its terminating null character.
25-
u32::try_from(len.checked_add(1).unwrap()).unwrap()
25+
u32::try_from(len).unwrap()
2626
}
2727
}
2828

src/shims/os_str.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
9292
/// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying
9393
/// to write if `size` is not large enough to fit the contents of `os_string` plus a null
9494
/// terminator. It returns `Ok((true, length))` if the writing process was successful. The
95-
/// string length returned does not include the null terminator.
95+
/// string length returned does include the null terminator.
9696
fn write_os_str_to_c_str(
9797
&mut self,
9898
os_str: &OsStr,
@@ -103,7 +103,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
103103
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
104104
// terminator to memory using the `ptr` pointer would cause an out-of-bounds access.
105105
let string_length = u64::try_from(bytes.len()).unwrap();
106-
if size <= string_length {
106+
let string_length = string_length.checked_add(1).unwrap();
107+
if size < string_length {
107108
return Ok((false, string_length));
108109
}
109110
self.eval_context_mut()
@@ -115,7 +116,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
115116
/// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying
116117
/// to write if `size` is not large enough to fit the contents of `os_string` plus a null
117118
/// terminator. It returns `Ok((true, length))` if the writing process was successful. The
118-
/// string length returned does not include the null terminator.
119+
/// string length returned does include the null terminator. Length is measured in units of
120+
/// `u16.`
119121
fn write_os_str_to_wide_str(
120122
&mut self,
121123
os_str: &OsStr,
@@ -157,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
157159
alloc
158160
.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar).into())?;
159161
}
160-
Ok((true, string_length - 1))
162+
Ok((true, string_length))
161163
}
162164

163165
/// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.

src/shims/unix/foreign_items.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
553553
this.write_int(super::UID, dest)?;
554554
}
555555

556+
"getpwuid_r" if this.frame_in_std() => {
557+
let [uid, pwd, buf, buflen, result] =
558+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
559+
this.check_no_isolation("`getpwuid_r`")?;
560+
561+
let uid = this.read_scalar(uid)?.to_u32()?;
562+
let pwd = this.deref_operand(pwd)?;
563+
let buf = this.read_pointer(buf)?;
564+
let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?;
565+
let result = this.deref_operand(result)?;
566+
567+
// Must be for "us".
568+
if uid != crate::shims::unix::UID {
569+
throw_unsup_format!("`getpwuid_r` on other users is not supported");
570+
}
571+
572+
// Reset all fields to `uninit` to make sure nobody reads them.
573+
// (This is a std-only shim so we are okay with such hacks.)
574+
this.write_uninit(&pwd.into())?;
575+
576+
// We only set the home_dir field.
577+
#[allow(deprecated)]
578+
let home_dir = std::env::home_dir().unwrap();
579+
let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
580+
let pw_dir = this.mplace_field_named(&pwd, "pw_dir")?;
581+
this.write_pointer(buf, &pw_dir.into())?;
582+
583+
if written {
584+
this.write_pointer(pwd.ptr, &result.into())?;
585+
this.write_null(dest)?;
586+
} else {
587+
this.write_null(&result.into())?;
588+
this.write_scalar(this.eval_libc("ERANGE")?, dest)?;
589+
}
590+
}
591+
556592
// Platform-specific shims
557593
_ => {
558594
match this.tcx.sess.target.os.as_ref() {

src/shims/unix/fs.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1380,11 +1380,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
13801380
let name_place = this.mplace_field(&entry_place, 5)?;
13811381

13821382
let file_name = dir_entry.file_name(); // not a Path as there are no separators!
1383-
let (name_fits, file_name_len) = this.write_os_str_to_c_str(
1383+
let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str(
13841384
&file_name,
13851385
name_place.ptr,
13861386
name_place.layout.size.bytes(),
13871387
)?;
1388+
let file_name_len = file_name_buf_len.checked_sub(1).unwrap();
13881389
if !name_fits {
13891390
throw_unsup_format!(
13901391
"a directory entry had a name too large to fit in libc::dirent"

src/shims/unix/linux/foreign_items.rs

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -155,41 +155,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
155155
this.write_null(dest)?;
156156
}
157157

158-
"getpwuid_r" if this.frame_in_std() => {
159-
let [uid, pwd, buf, buflen, result] =
160-
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
161-
this.check_no_isolation("`getpwuid_r`")?;
162-
163-
let uid = this.read_scalar(uid)?.to_u32()?;
164-
let pwd = this.deref_operand(pwd)?;
165-
let buf = this.read_pointer(buf)?;
166-
let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?;
167-
let result = this.deref_operand(result)?;
168-
169-
// Must be for "us".
170-
if uid != crate::shims::unix::UID {
171-
throw_unsup_format!("`getpwuid_r` on other users is not supported");
172-
}
173-
174-
// Reset all fields to `uninit` to make sure nobody reads them.
175-
this.write_uninit(&pwd.into())?;
176-
177-
// We only set the home_dir field.
178-
#[allow(deprecated)]
179-
let home_dir = std::env::home_dir().unwrap();
180-
let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
181-
let pw_dir = this.mplace_field_named(&pwd, "pw_dir")?;
182-
this.write_pointer(buf, &pw_dir.into())?;
183-
184-
if written {
185-
this.write_pointer(pwd.ptr, &result.into())?;
186-
this.write_null(dest)?;
187-
} else {
188-
this.write_null(&result.into())?;
189-
this.write_scalar(this.eval_libc("ERANGE")?, dest)?;
190-
}
191-
}
192-
193158
_ => return Ok(EmulateByNameResult::NotSupported),
194159
};
195160

src/shims/unix/macos/foreign_items.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
117117
dest,
118118
)?;
119119
}
120+
"_NSGetExecutablePath" => {
121+
let [buf, bufsize] =
122+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
123+
this.check_no_isolation("`_NSGetExecutablePath`")?;
124+
125+
let buf_ptr = this.read_pointer(buf)?;
126+
let bufsize = this.deref_operand(bufsize)?;
127+
128+
// Using the host current_exe is a bit off, but consistent with Linux
129+
// (where stdlib reads /proc/self/exe).
130+
let path = std::env::current_exe().unwrap();
131+
let (written, size_needed) = this.write_path_to_c_str(
132+
&path,
133+
buf_ptr,
134+
this.read_scalar(&bufsize.into())?.to_u32()?.into(),
135+
)?;
136+
137+
if written {
138+
this.write_null(dest)?;
139+
} else {
140+
this.write_scalar(
141+
Scalar::from_u32(size_needed.try_into().unwrap()),
142+
&bufsize.into(),
143+
)?;
144+
this.write_int(-1, dest)?;
145+
}
146+
}
120147

121148
// Thread-local storage
122149
"_tlv_atexit" => {
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)