Skip to content

Commit f1e8c54

Browse files
committed
Auto merge of rust-lang#3776 - oli-obk:duplicator, r=oli-obk
Use Scalar consistently in foreign item emulation Step 0 of rust-lang#3772 This just makes the code consistent. While we could also go for consistency the other way, that would only allow us to use integers in some cases where we use `Scalar` right now, because `Scalar` can also hold pointers where applicable. There's also no danger in messing up (even though we do lose some compile-time checks), as `Scalar` knows the size of the integer stored within, so it will check that against the destination when it is written. In fact, this makes the checks much stronger compared with `write_int`, which just checks that the integer fits into the destination size.
2 parents cf63c16 + 6fc1b69 commit f1e8c54

File tree

10 files changed

+239
-245
lines changed

10 files changed

+239
-245
lines changed

src/tools/miri/src/shims/time.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
9393
Ok(Scalar::from_i32(0))
9494
}
9595

96-
fn gettimeofday(&mut self, tv_op: &OpTy<'tcx>, tz_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
96+
fn gettimeofday(
97+
&mut self,
98+
tv_op: &OpTy<'tcx>,
99+
tz_op: &OpTy<'tcx>,
100+
) -> InterpResult<'tcx, Scalar> {
97101
let this = self.eval_context_mut();
98102

99103
this.assert_target_os_is_unix("gettimeofday");
@@ -106,7 +110,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
106110
if !this.ptr_is_null(tz)? {
107111
let einval = this.eval_libc("EINVAL");
108112
this.set_last_error(einval)?;
109-
return Ok(-1);
113+
return Ok(Scalar::from_i32(-1));
110114
}
111115

112116
let duration = system_time_to_duration(&SystemTime::now())?;
@@ -115,7 +119,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
115119

116120
this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &tv)?;
117121

118-
Ok(0)
122+
Ok(Scalar::from_i32(0))
119123
}
120124

121125
// The localtime() function shall convert the time in seconds since the Epoch pointed to by
@@ -308,7 +312,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
308312
&mut self,
309313
req_op: &OpTy<'tcx>,
310314
_rem: &OpTy<'tcx>, // Signal handlers are not supported, so rem will never be written to.
311-
) -> InterpResult<'tcx, i32> {
315+
) -> InterpResult<'tcx, Scalar> {
312316
let this = self.eval_context_mut();
313317

314318
this.assert_target_os_is_unix("nanosleep");
@@ -320,7 +324,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
320324
None => {
321325
let einval = this.eval_libc("EINVAL");
322326
this.set_last_error(einval)?;
323-
return Ok(-1);
327+
return Ok(Scalar::from_i32(-1));
324328
}
325329
};
326330

@@ -333,7 +337,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
333337
@timeout = |_this| { Ok(()) }
334338
),
335339
);
336-
Ok(0)
340+
Ok(Scalar::from_i32(0))
337341
}
338342

339343
#[allow(non_snake_case)]

src/tools/miri/src/shims/unix/env.rs

+19-21
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
148148
Ok(var_ptr.unwrap_or_else(Pointer::null))
149149
}
150150

151-
fn setenv(&mut self, name_op: &OpTy<'tcx>, value_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
151+
fn setenv(
152+
&mut self,
153+
name_op: &OpTy<'tcx>,
154+
value_op: &OpTy<'tcx>,
155+
) -> InterpResult<'tcx, Scalar> {
152156
let this = self.eval_context_mut();
153157
this.assert_target_os_is_unix("setenv");
154158

@@ -169,16 +173,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
169173
this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
170174
}
171175
this.update_environ()?;
172-
Ok(0) // return zero on success
176+
Ok(Scalar::from_i32(0)) // return zero on success
173177
} else {
174178
// name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
175179
let einval = this.eval_libc("EINVAL");
176180
this.set_last_error(einval)?;
177-
Ok(-1)
181+
Ok(Scalar::from_i32(-1))
178182
}
179183
}
180184

181-
fn unsetenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
185+
fn unsetenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
182186
let this = self.eval_context_mut();
183187
this.assert_target_os_is_unix("unsetenv");
184188

@@ -195,12 +199,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
195199
this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
196200
}
197201
this.update_environ()?;
198-
Ok(0)
202+
Ok(Scalar::from_i32(0))
199203
} else {
200204
// name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
201205
let einval = this.eval_libc("EINVAL");
202206
this.set_last_error(einval)?;
203-
Ok(-1)
207+
Ok(Scalar::from_i32(-1))
204208
}
205209
}
206210

@@ -232,7 +236,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
232236
Ok(Pointer::null())
233237
}
234238

235-
fn chdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> {
239+
fn chdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
236240
let this = self.eval_context_mut();
237241
this.assert_target_os_is_unix("chdir");
238242

@@ -242,16 +246,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
242246
this.reject_in_isolation("`chdir`", reject_with)?;
243247
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
244248

245-
return Ok(-1);
249+
return Ok(Scalar::from_i32(-1));
246250
}
247251

248-
match env::set_current_dir(path) {
249-
Ok(()) => Ok(0),
250-
Err(e) => {
251-
this.set_last_error_from_io_error(e)?;
252-
Ok(-1)
253-
}
254-
}
252+
let result = env::set_current_dir(path).map(|()| 0);
253+
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
255254
}
256255

257256
/// Updates the `environ` static.
@@ -270,18 +269,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
270269
Ok(())
271270
}
272271

273-
fn getpid(&mut self) -> InterpResult<'tcx, i32> {
272+
fn getpid(&mut self) -> InterpResult<'tcx, Scalar> {
274273
let this = self.eval_context_mut();
275274
this.assert_target_os_is_unix("getpid");
276275

277276
// The reason we need to do this wacky of a conversion is because
278277
// `libc::getpid` returns an i32, however, `std::process::id()` return an u32.
279278
// So we un-do the conversion that stdlib does and turn it back into an i32.
280-
#[allow(clippy::cast_possible_wrap)]
281-
Ok(this.get_pid() as i32)
279+
// In `Scalar` representation, these are the same, so we don't need to anything else.
280+
Ok(Scalar::from_u32(this.get_pid()))
282281
}
283282

284-
fn linux_gettid(&mut self) -> InterpResult<'tcx, i32> {
283+
fn linux_gettid(&mut self) -> InterpResult<'tcx, Scalar> {
285284
let this = self.eval_context_ref();
286285
this.assert_target_os("linux", "gettid");
287286

@@ -290,7 +289,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
290289
// Compute a TID for this thread, ensuring that the main thread has PID == TID.
291290
let tid = this.get_pid().strict_add(index);
292291

293-
#[allow(clippy::cast_possible_wrap)]
294-
Ok(tid as i32)
292+
Ok(Scalar::from_u32(tid))
295293
}
296294
}

src/tools/miri/src/shims/unix/fd.rs

+24-23
Original file line numberDiff line numberDiff line change
@@ -310,20 +310,20 @@ impl FdTable {
310310

311311
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
312312
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
313-
fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, i32> {
313+
fn dup(&mut self, old_fd: i32) -> InterpResult<'tcx, Scalar> {
314314
let this = self.eval_context_mut();
315315

316316
let Some(dup_fd) = this.machine.fds.dup(old_fd) else {
317-
return this.fd_not_found();
317+
return Ok(Scalar::from_i32(this.fd_not_found()?));
318318
};
319-
Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, 0))
319+
Ok(Scalar::from_i32(this.machine.fds.insert_fd_with_min_fd(dup_fd, 0)))
320320
}
321321

322-
fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, i32> {
322+
fn dup2(&mut self, old_fd: i32, new_fd: i32) -> InterpResult<'tcx, Scalar> {
323323
let this = self.eval_context_mut();
324324

325325
let Some(dup_fd) = this.machine.fds.dup(old_fd) else {
326-
return this.fd_not_found();
326+
return Ok(Scalar::from_i32(this.fd_not_found()?));
327327
};
328328
if new_fd != old_fd {
329329
// Close new_fd if it is previously opened.
@@ -333,7 +333,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
333333
file_description.close(this.machine.communicate())?.ok();
334334
}
335335
}
336-
Ok(new_fd)
336+
Ok(Scalar::from_i32(new_fd))
337337
}
338338

339339
fn flock(&mut self, fd: i32, op: i32) -> InterpResult<'tcx, Scalar> {
@@ -370,7 +370,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
370370
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
371371
}
372372

373-
fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> {
373+
fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
374374
let this = self.eval_context_mut();
375375

376376
if args.len() < 2 {
@@ -388,11 +388,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
388388
// `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
389389
// always sets this flag when opening a file. However we still need to check that the
390390
// file itself is open.
391-
if this.machine.fds.is_fd(fd) {
392-
Ok(this.eval_libc_i32("FD_CLOEXEC"))
391+
Ok(Scalar::from_i32(if this.machine.fds.is_fd(fd) {
392+
this.eval_libc_i32("FD_CLOEXEC")
393393
} else {
394-
this.fd_not_found()
395-
}
394+
this.fd_not_found()?
395+
}))
396396
} else if cmd == this.eval_libc_i32("F_DUPFD")
397397
|| cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")
398398
{
@@ -409,15 +409,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
409409
let start = this.read_scalar(&args[2])?.to_i32()?;
410410

411411
match this.machine.fds.dup(fd) {
412-
Some(dup_fd) => Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, start)),
413-
None => this.fd_not_found(),
412+
Some(dup_fd) =>
413+
Ok(Scalar::from_i32(this.machine.fds.insert_fd_with_min_fd(dup_fd, start))),
414+
None => Ok(Scalar::from_i32(this.fd_not_found()?)),
414415
}
415416
} else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") {
416417
// Reject if isolation is enabled.
417418
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
418419
this.reject_in_isolation("`fcntl`", reject_with)?;
419420
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
420-
return Ok(-1);
421+
return Ok(Scalar::from_i32(-1));
421422
}
422423

423424
this.ffullsync_fd(fd)
@@ -462,7 +463,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
462463
buf: Pointer,
463464
count: u64,
464465
offset: Option<i128>,
465-
) -> InterpResult<'tcx, i64> {
466+
) -> InterpResult<'tcx, Scalar> {
466467
let this = self.eval_context_mut();
467468

468469
// Isolation check is done via `FileDescriptor` trait.
@@ -482,7 +483,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
482483
// We temporarily dup the FD to be able to retain mutable access to `this`.
483484
let Some(fd) = this.machine.fds.dup(fd) else {
484485
trace!("read: FD not found");
485-
return this.fd_not_found();
486+
return Ok(Scalar::from_target_isize(this.fd_not_found()?, this));
486487
};
487488

488489
trace!("read: FD mapped to {fd:?}");
@@ -496,7 +497,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
496497
let Ok(offset) = u64::try_from(offset) else {
497498
let einval = this.eval_libc("EINVAL");
498499
this.set_last_error(einval)?;
499-
return Ok(-1);
500+
return Ok(Scalar::from_target_isize(-1, this));
500501
};
501502
fd.borrow_mut().pread(communicate, &mut bytes, offset, this)
502503
}
@@ -513,11 +514,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
513514
buf,
514515
bytes[..usize::try_from(read_bytes).unwrap()].iter().copied(),
515516
)?;
516-
Ok(read_bytes)
517+
Ok(Scalar::from_target_isize(read_bytes, this))
517518
}
518519
Err(e) => {
519520
this.set_last_error_from_io_error(e)?;
520-
Ok(-1)
521+
Ok(Scalar::from_target_isize(-1, this))
521522
}
522523
}
523524
}
@@ -528,7 +529,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
528529
buf: Pointer,
529530
count: u64,
530531
offset: Option<i128>,
531-
) -> InterpResult<'tcx, i64> {
532+
) -> InterpResult<'tcx, Scalar> {
532533
let this = self.eval_context_mut();
533534

534535
// Isolation check is done via `FileDescriptor` trait.
@@ -546,7 +547,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
546547
let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?.to_owned();
547548
// We temporarily dup the FD to be able to retain mutable access to `this`.
548549
let Some(fd) = this.machine.fds.dup(fd) else {
549-
return this.fd_not_found();
550+
return Ok(Scalar::from_target_isize(this.fd_not_found()?, this));
550551
};
551552

552553
let result = match offset {
@@ -555,15 +556,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
555556
let Ok(offset) = u64::try_from(offset) else {
556557
let einval = this.eval_libc("EINVAL");
557558
this.set_last_error(einval)?;
558-
return Ok(-1);
559+
return Ok(Scalar::from_target_isize(-1, this));
559560
};
560561
fd.borrow_mut().pwrite(communicate, &bytes, offset, this)
561562
}
562563
};
563564
drop(fd);
564565

565566
let result = result?.map(|c| i64::try_from(c).unwrap());
566-
this.try_unwrap_io_result(result)
567+
Ok(Scalar::from_target_isize(this.try_unwrap_io_result(result)?, this))
567568
}
568569
}
569570

0 commit comments

Comments
 (0)