-
Notifications
You must be signed in to change notification settings - Fork 349
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a helper for directly writing io::Result
to places
#3777
Conversation
Instead of having to repeat the conversion to `Scalar`
@@ -857,19 +857,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | |||
/// | |||
/// This function uses `T: From<i32>` instead of `i32` directly because some IO related | |||
/// functions return different integer types (like `read`, that returns an `i64`). | |||
fn try_unwrap_io_result<T: From<i32>>( | |||
fn try_unwrap_io_result<T: WriteIoResult>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The doc comment above is outdated now.
@@ -1434,3 +1447,35 @@ pub(crate) fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { | |||
u32::try_from(len).unwrap() | |||
} | |||
} | |||
|
|||
pub trait WriteIoResult { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a doc comment. Also the trait name is kind of confusing, maybe a doc comment will help coming up with a better one.
Ok(written_bytes) => Ok(Scalar::from_target_isize(written_bytes, this)), | ||
Err(e) => { | ||
this.set_last_error_from_io_error(e)?; | ||
Ok(Scalar::from_target_isize(-1, this)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code got worse than it used to be, what's happening here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are writing target sized integers, so i'll need to add a helper type to wrap the i64
s in. The read method already could not be ported before and was written out fully. I want to fix both at the same time
let result = remove_dir(path).map(|_| 0i32); | ||
|
||
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) | ||
Ok(remove_dir(path)) | ||
} | ||
|
||
fn opendir(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this one still return Scalar
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It (and others) return error codes via this.eval_libc("EACCES");
without a corresponding ErrorKind
existing in libcore. I plan to use an error enum that wraps io errors and has variants for all the eval_libc errors we use in miri. May turn out overkill, but I wanna see how it looks before discarding it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems easier to use Scalar
as the universal type for what to store in errno -- we can already convert both io::Error
and libc constants into Scalar
.
@@ -78,7 +78,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | |||
"chdir" => { | |||
let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; | |||
let result = this.chdir(path)?; | |||
this.write_scalar(result, dest)?; | |||
this.write_io_result(result, dest)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it really such a big win to move the io::Result handling out of the shim?
A priori I think I'd prefer the version that returns a Scalar, as that matches the C function we're implementing and since it is a pattern we can use for all functions, not just IO functions. We can have more helpers inside those functions that make them easier to write and avoid hard-coding -1
anywhere, that seems like a more promising approach to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I initially wanted to add such helpers, but then it got annoying for handling i64
, i32
, and i64 but is actually target usize
, as that would require explicit type annotations and reliance on runtime checks (Scalar size vs destination size). I then thought it would be nicer to keep some semblence of result handling around, as now all the return types must match up again, like before moving to scalars. I'll finish this PR to its conclusion and open a separate PR for just using helpers everywhere so you can compare.
let this = self.eval_context_mut(); | ||
|
||
let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; | ||
|
||
// Reject if isolation is enabled. | ||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { | ||
this.reject_in_isolation("`rmdir`", reject_with)?; | ||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; | ||
return Ok(Scalar::from_i32(-1)); | ||
return Ok(Err(ErrorKind::PermissionDenied.into())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For instance, this could become return Ok(this.return_io_error(ErrorKind::PermissionDenied.into()))
where return_io_error
sets the errno and then returns -1
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, but I'd still need to say how big the scalar is supposed to be. Not the end of the world, but also not nice
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right, the type...
Another option might be to pass dest
to these functions and not have them return anything. A function that blocks usually already needs to do that anyway. Then they can use your new write_io_result
internally for when they naturally have an io::Result
, and some write_io_error
for cases like this where we hard-code an error.
I think the other scheme will allow us to better simplify things, so I'm closing this PR and will cherry-pick the parts that are useful |
Instead of having to repeat the conversion to
Scalar
everywhere.