-
Notifications
You must be signed in to change notification settings - Fork 379
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
fix: avoid stopping machine upon running env operations in isolation #1797
Conversation
Thanks for the PR! I recall suggesting something similar in the past, but the concern back then was that we should do this consistently for all operations. So this certainly does not fix #1034, as there are more operations that would need adjustment (getenv/setenv, all the file system operations -- basically everything that checks the The other concern was discoverability: when such an operation fails, it can be hard for users to figure out why, since they might not expect the "isolation" Miri provides. I am not sure what is the best solution to this. Maybe keep the errors by default but offer a flag to let evaluation continue instead? I am not sure what your usecase is here so I cannot tell if that would help you or not. Cc @oli-obk |
Cc @Aaron1011 |
We could turn the errors into warnings and possibly add a flag to turn them off entirely (which the warning could then mention) |
What to do with the rest of the operations was gonna be my next question based on the feedback 🙂 I'll drop "fixes" line so that issue is not closed. As for the question of discoverability, I'm trying to understand the problem:
|
Yes. (Even more strongly, Miri in isolation mode should be completely pure, deterministic, repeatable.)
Yes.
Indeed I think this is a reasonable approach -- but I don't think we can return an "explicit message" to the caller, all we have is an error code. I assume a lot of code out there will So I like @oli-obk's proposal of having Miri itself print a warning (we already have infrastructure for that, see So:
At some point we might add a flag to suppress the warning, but that does not have to happen immediately. |
Supported where, in the Miri mapping to raw error codes? We can easily extend that. Which error code might a real Windows emit if the permission to change the current dir was denied? |
☔ The latest upstream changes (presumably #1801) made this pull request unmergeable. Please resolve the merge conflicts. |
@atsmtat I see you did a rebase; I am still setting the "waiting-on-author" flag based on the discussion above. If anything is unclear or if you think the ball is in our court and you need more feedback/review/help, please let me know. :) |
Yes, I tried out
|
Right, Miri mapping to raw error codes. I'll add appropriate Windows error codes. |
What do you think about a warning with a span like this:
I got the span from the top frame. Still not very helpful. Good to print user frame which calls into std. Is there a way to get such frame or it doesn't make sense? If you can point out an example where something like this is done, it'll be great. |
Diagnostics are deduplicated, so if the warning message is identical, it will only be printed once. |
Yes that was deliberate -- we don't want tons of warnings when a program does such a call in a loop. |
Looks like I'll push these changes soon. Let me know what you think :) |
@RalfJung I updated the PR with options for user visibility. assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::NotFound);
for _i in 0..3 {
assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::NotFound);
} Output of default run (with isolation, without any flags):
Output of run with
Running with |
I wasn't sure about running rustfmt, so I haven't run it on my changes. |
src/diagnostics.rs
Outdated
@@ -279,6 +280,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | |||
CreatedCallId(id) => format!("function call with id {}", id), | |||
CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), | |||
FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), | |||
DummyOpInIsolation(op) => format!("produced dummy error for `{}`", op), |
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 don't know what you mean by "dummy" error. I suggest to say something more like "{}
was made to return an error due to isolation" or so (and print a hint mentioning -Zmiri-disable-isolation
).
After rebasing onto latest master, running
In terms of deduplication, this looks great. :) I think we should adjust the messages a little. I don't think "note: tracking was triggered" makes sense, I'd more like to see something like "warning: operation rejected by isolation" or so. |
Updated output:
With
|
How do I run
|
|
☔ The latest upstream changes (presumably #1776) made this pull request unmergeable. Please resolve the merge conflicts. |
@RalfJung I've addressed your latest comments in recent commits. I believe you'd prefer I squash my branch commits. If so, let me know. |
LGTM, assuming CI passes and pending the rename of "ignore". :) |
Ah, and yes please squash the commits. |
I renamed "ignore" and squashed the commits. Waiting for your approval to run CI. |
src/shims/env.rs
Outdated
this.check_no_isolation("`getcwd`")?; | ||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { | ||
this.reject_in_isolation("getcwd", reject_with)?; | ||
let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); |
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, I forgot about one discussion we had: didn't we say this should be PermissionDenied
? And some match
for windows error conversions should be extended?
If you don't want to do this now, please leave FIXME in the code to change the error type.
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.
Also we should probably change set_last_error_from_io_error
to take an error kind so that we don't have to make up a string here. But that, too, could be a separate PR if you prefer.
Sorry I forgot about these things in my last round of review.
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.
so that we don't have to make up a string here.
I believe you could also use Error::from(ErrorKind::...)
or ErrorKind::....into()
to avoid the string:
https://doc.rust-lang.org/nightly/std/io/struct.Error.html#impl-From%3CErrorKind%3E
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.
But is there even any reason that set_last_error_from_io_error
would take more than an ErrorKind
?
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 specifically used Error::new
as it allows custom payload for error not originated from OS. Quoting its documentation -- This function is used to generically create I/O errors which do not originate from the OS itself.
. Shouldn't we use a custom message indicating that the problem is due to isolation so that user doesn't confuse it with an actual OS error? Or the intention is to make the distinction not clear?
As for which code to generate, yes, I mentioned using PermissionDenied
earlier. But then, if it's a bogus error, does it matter?
For Windows code, I didn't want to mix it with this PR which is mainly about adding this new setup. I'll create a new PR for it. Also, we still have quite a few shims using old "always abort" setup, which I was planning to convert in next PR(s). Otherwise this new flag isn't very useful 🙂
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.
But is there even any reason that
set_last_error_from_io_error
would take more than anErrorKind
?
No, I don't think so. I'm just pointing out an option if that function is not going to be changed as part of this PR.
Shouldn't we use a custom message indicating that the problem is due to isolation so that user doesn't confuse it with an actual OS error?
The set_last_error_from_io_error()
function only uses e.kind()
, so I think the message will be discarded anyway.
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, I didn't see that. Thanks for pointing out. I guess I can change it to take ErrorKind
. @RalfJung Do you prefer I do it in this PR?
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.
Do you prefer I do it in this PR?
Yeah I think that would be better. Thanks. :)
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.
Fixed the parameter in a new commit, which I didn't squash as it's independent from the first commit.
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.
Thanks a lot. :)
I think we probably want to change to a different error code, but we can do that later.
In user interface, added a new flag `-Zmiri-isolation-error` which takes one of the four values -- hide, warn, warn-nobacktrace, and abort. This option can be used to configure Miri to either abort or return an error code upon executing isolated op. If not aborted, Miri prints a warning, whose verbosity can be configured using this flag. In implementation, added a new enum `IsolatedOp` to capture all the settings related to ops requiring communication with the host. Old `communicate` flag in both miri configs and machine stats is replaced with a new helper function `communicate()` which checks `isolated_op` internally. Added a new helper function `reject_in_isolation` which can be called by shims to reject ops according to the reject_with settings. Use miri specific diagnostics function `report_msg` to print backtrace in the warning. Update it to take an enum value instead of a bool, indicating the level of diagnostics. Updated shims related to current dir to use the new APIs. Added a new test for current dir ops in isolation without halting machine.
`set_last_error_from_io_error` works with only the error kind, and discards the payload. Fix its signature to make it explicit.
📌 Commit ba64f48 has been approved by |
☀️ Test successful - checks-actions |
isolated operations return EPERM; tweak isolation hint Follow-up to #1797
get and set current dir operations used to halt the machine by
throwing an exception in isolation mode. This change updates them to
return a dummy
NotFound
error instead, and keep the machine running.I started with a custom error using
ErrorKind::Other
, but since itcan't be mapped to a raw OS error, I dropped it.
NotFound
kind of makesense for get operations, but not much for set operations. But that's
the only error supported for windows currently.