Skip to content

Commit af3923b

Browse files
committed
Auto merge of #991 - christianpoveda:errno-place, r=RalfJung
Change the last OS error location to a place r? @RalfJung
2 parents f912a8b + 9d50c5e commit af3923b

File tree

6 files changed

+76
-61
lines changed

6 files changed

+76
-61
lines changed

src/eval.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
183183
let errno_layout = ecx.layout_of(ecx.tcx.types.u32)?;
184184
let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into());
185185
ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
186-
let errno_ptr = ecx.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?;
187-
ecx.machine.last_error = errno_ptr;
186+
ecx.machine.last_error = Some(errno_place);
188187

189188
Ok(ecx)
190189
}

src/helpers.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,4 +345,68 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
345345
}
346346
Ok(())
347347
}
348+
349+
/// Sets the last error variable.
350+
fn set_last_error(&mut self, scalar: Scalar<Tag>) -> InterpResult<'tcx> {
351+
let this = self.eval_context_mut();
352+
let errno_place = this.machine.last_error.unwrap();
353+
this.write_scalar(scalar, errno_place.into())
354+
}
355+
356+
/// Gets the last error variable.
357+
fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar<Tag>> {
358+
let this = self.eval_context_mut();
359+
let errno_place = this.machine.last_error.unwrap();
360+
this.read_scalar(errno_place.into())?.not_undef()
361+
}
362+
363+
/// Sets the last OS error using a `std::io::Error`. This function tries to produce the most
364+
/// similar OS error from the `std::io::ErrorKind` and sets it as the last OS error.
365+
fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> {
366+
use std::io::ErrorKind::*;
367+
let this = self.eval_context_mut();
368+
let target = &this.tcx.tcx.sess.target.target;
369+
let last_error = if target.options.target_family == Some("unix".to_owned()) {
370+
this.eval_libc(match e.kind() {
371+
ConnectionRefused => "ECONNREFUSED",
372+
ConnectionReset => "ECONNRESET",
373+
PermissionDenied => "EPERM",
374+
BrokenPipe => "EPIPE",
375+
NotConnected => "ENOTCONN",
376+
ConnectionAborted => "ECONNABORTED",
377+
AddrNotAvailable => "EADDRNOTAVAIL",
378+
AddrInUse => "EADDRINUSE",
379+
NotFound => "ENOENT",
380+
Interrupted => "EINTR",
381+
InvalidInput => "EINVAL",
382+
TimedOut => "ETIMEDOUT",
383+
AlreadyExists => "EEXIST",
384+
WouldBlock => "EWOULDBLOCK",
385+
_ => throw_unsup_format!("The {} error cannot be transformed into a raw os error", e)
386+
})?
387+
} else {
388+
// FIXME: we have to implement the windows' equivalent of this.
389+
throw_unsup_format!("Setting the last OS error from an io::Error is unsupported for {}.", target.target_os)
390+
};
391+
this.set_last_error(last_error)
392+
}
393+
394+
/// Helper function that consumes an `std::io::Result<T>` and returns an
395+
/// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns
396+
/// `Ok(-1)` and sets the last OS error accordingly.
397+
///
398+
/// This function uses `T: From<i32>` instead of `i32` directly because some IO related
399+
/// functions return different integer types (like `read`, that returns an `i64`)
400+
fn try_unwrap_io_result<T: From<i32>>(
401+
&mut self,
402+
result: std::io::Result<T>,
403+
) -> InterpResult<'tcx, T> {
404+
match result {
405+
Ok(ok) => Ok(ok),
406+
Err(e) => {
407+
self.eval_context_mut().set_last_error_from_io_error(e)?;
408+
Ok((-1).into())
409+
}
410+
}
411+
}
348412
}

src/machine.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ pub struct Evaluator<'tcx> {
9191
pub(crate) argv: Option<Pointer<Tag>>,
9292
pub(crate) cmd_line: Option<Pointer<Tag>>,
9393

94-
/// Last OS error.
95-
pub(crate) last_error: Option<Pointer<Tag>>,
94+
/// Last OS error location in memory. It is a 32-bit integer
95+
pub(crate) last_error: Option<MPlaceTy<'tcx, Tag>>,
9696

9797
/// TLS state.
9898
pub(crate) tls: TlsData<'tcx>,

src/shims/env.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
146146
let erange = this.eval_libc("ERANGE")?;
147147
this.set_last_error(erange)?;
148148
}
149-
Err(e) => this.consume_io_error(e)?,
149+
Err(e) => this.set_last_error_from_io_error(e)?,
150150
}
151151
Ok(Scalar::ptr_null(&*this.tcx))
152152
}
@@ -168,7 +168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
168168
match env::set_current_dir(path) {
169169
Ok(()) => Ok(0),
170170
Err(e) => {
171-
this.consume_io_error(e)?;
171+
this.set_last_error_from_io_error(e)?;
172172
Ok(-1)
173173
}
174174
}

src/shims/foreign_items.rs

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
414414
}
415415

416416
"__errno_location" | "__error" => {
417-
let errno_scalar: Scalar<Tag> = this.machine.last_error.unwrap().into();
418-
this.write_scalar(errno_scalar, dest)?;
417+
let errno_place = this.machine.last_error.unwrap();
418+
this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?;
419419
}
420420

421421
"getenv" => {
@@ -977,34 +977,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
977977
}
978978
return Ok(None);
979979
}
980-
981-
fn set_last_error(&mut self, scalar: Scalar<Tag>) -> InterpResult<'tcx> {
982-
let this = self.eval_context_mut();
983-
let errno_ptr = this.machine.last_error.unwrap();
984-
// We allocated this during machine initialziation so the bounds are fine.
985-
this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar(
986-
&*this.tcx,
987-
errno_ptr,
988-
scalar.into(),
989-
Size::from_bits(32),
990-
)
991-
}
992-
993-
fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar<Tag>> {
994-
let this = self.eval_context_mut();
995-
let errno_ptr = this.machine.last_error.unwrap();
996-
this.memory
997-
.get(errno_ptr.alloc_id)?
998-
.read_scalar(&*this.tcx, errno_ptr, Size::from_bits(32))?
999-
.not_undef()
1000-
}
1001-
1002-
fn consume_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> {
1003-
self.eval_context_mut().set_last_error(Scalar::from_int(
1004-
e.raw_os_error().unwrap(),
1005-
Size::from_bits(32),
1006-
))
1007-
}
1008980
}
1009981

1010982
// Shims the linux 'getrandom()' syscall.

src/shims/fs.rs

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
108108
fh.low
109109
});
110110

111-
this.consume_result(fd)
111+
this.try_unwrap_io_result(fd)
112112
}
113113

114114
fn fcntl(
@@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
144144
let fd = this.read_scalar(fd_op)?.to_i32()?;
145145

146146
this.remove_handle_and(fd, |handle, this| {
147-
this.consume_result(handle.file.sync_all().map(|_| 0i32))
147+
this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32))
148148
})
149149
}
150150

@@ -175,9 +175,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
175175
.get_bytes_mut(&*this.tcx, buf, Size::from_bytes(count))
176176
.map(|buffer| handle.file.read(buffer))
177177
});
178-
// Reinsert the file handle
179178
this.machine.file_handler.handles.insert(fd, handle).unwrap_none();
180-
this.consume_result(bytes?.map(|bytes| bytes as i64))
179+
this.try_unwrap_io_result(bytes?.map(|bytes| bytes as i64))
181180
})
182181
}
183182

@@ -206,7 +205,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
206205
.map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64))
207206
});
208207
this.machine.file_handler.handles.insert(fd, handle).unwrap_none();
209-
this.consume_result(bytes?)
208+
this.try_unwrap_io_result(bytes?)
210209
})
211210
}
212211

@@ -223,7 +222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
223222

224223
let result = remove_file(path).map(|_| 0);
225224

226-
this.consume_result(result)
225+
this.try_unwrap_io_result(result)
227226
}
228227

229228
/// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it
@@ -271,23 +270,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
271270
Ok((-1).into())
272271
}
273272
}
274-
275-
/// Helper function that consumes an `std::io::Result<T>` and returns an
276-
/// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an
277-
/// OS error using `std::io::Error::raw_os_error`.
278-
///
279-
/// This function uses `T: From<i32>` instead of `i32` directly because some IO related
280-
/// functions return different integer types (like `read`, that returns an `i64`)
281-
fn consume_result<T: From<i32>>(
282-
&mut self,
283-
result: std::io::Result<T>,
284-
) -> InterpResult<'tcx, T> {
285-
match result {
286-
Ok(ok) => Ok(ok),
287-
Err(e) => {
288-
self.eval_context_mut().consume_io_error(e)?;
289-
Ok((-1).into())
290-
}
291-
}
292-
}
293273
}

0 commit comments

Comments
 (0)