Skip to content

Automatically distinguish between Miri identifying UB and Miri being unable to run tests #1908

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

Open
kupiakos opened this issue Nov 4, 2021 · 7 comments
Labels
A-ux Area: This affects the general user experience C-support Category: Not necessarily a bug, but someone asking for support

Comments

@kupiakos
Copy link

kupiakos commented Nov 4, 2021

Hi, I'm working on an automated test suite for our project with Miri, and we have a number of crates that use FFI in some, but not all, tests. I won't have knowledge about which crates and the tests within those crates call FFI functions.

Is there an easy way to handle this? We want to run as many of our tests as possible under Miri. Right now, my current strategy is to go through stderr after running cargo miri test on each crate and search through a set of fixed error strings that indicate Miri being unable to run the test rather than identifying UB. However, that's brittle and requires me to know upfront all of the possible unsupported features.

Could we have a different error code be returned for cargo miri test if a test was unable to finish running due to an unsupported feature? Right now both UB and unsupported features return 1.
If there were a flag to skip and ignore tests that couldn't run in Miri, that would also work.

@camelid
Copy link
Member

camelid commented Nov 4, 2021

If there were a flag to skip and ignore tests that couldn't run in Miri, that would also work.

Perhaps that could be a flag named something like -Zmiri-noop-on-unsupported, to be a companion to this flag described in the README:

-Zmiri-panic-on-unsupported will makes some forms of unsupported functionality, such as FFI and unsupported syscalls, panic within the context of the emulated application instead of raising an error within the context of Miri (and halting execution). Note that code might not expect these operations to ever panic, so this flag can lead to strange (mis)behavior.

@RalfJung
Copy link
Member

RalfJung commented Nov 4, 2021

If there were a flag to skip and ignore tests that couldn't run in Miri, that would also work.

I don't quite see how this could work.

Note that Miri does not have a concept of 'tests'. When you run Rust tests with cargo test or cargo miri test, what happens is that the libtest test harness is linked in and provides a main function, which is then compiled (by rustc) / interpreted (by Miri) as usual. So Miri doesn't even know that you are running a test suite, let alone where one test ends and the other begins. There is no fundamental difference between cargo miri run and cargo miri test. In both cases, Miri is just given a single entry point and perform evaluation of whatever code it finds there.

Perhaps that could be a flag named something like -Zmiri-noop-on-unsupported, to be a companion to this flag described in the README:

When the program calls some foreign function, Miri has to do something. A NOP is not an option. It can make all functions return 0 and ignore their arguments, but I doubt that would lead to useful results...

Could we have a different error code be returned for cargo miri test if a test was unable to finish running due to an unsupported feature? Right now both UB and unsupported features return 1.

That seems plausible. I do not know if anyone relies on the existing error codes, or how to determine useful error codes. Miri is basically a rustc backend; which error codes does rustc use?

AFAIK, the error code 1 currently comes from this call

compiler.session().abort_if_errors();

To make the error code dependent on the kind of error, we probably want to call process::exit ourselves in

pub fn report_error<'tcx, 'mir>(

@camelid
Copy link
Member

camelid commented Nov 4, 2021

Perhaps that could be a flag named something like -Zmiri-noop-on-unsupported, to be a companion to this flag described in the README:

When the program calls some foreign function, Miri has to do something. A NOP is not an option. It can make all functions return 0 and ignore their arguments, but I doubt that would lead to useful results...

Yeah, that makes sense. In theory, Miri could abort with a zero exit code if that flag were passed, but that'd be worse than just always returning a special error code for unsupported operations.

@kupiakos
Copy link
Author

kupiakos commented Nov 4, 2021

Note that Miri does not have a concept of 'tests'

Makes sense, though I do think it'd be possible to have the libtest harness override its behavior when running in Miri if there were a way to communicate this info, maybe by using -Zmiri-panic-on-unsupported. The test harness could identify the panic and determine whether it came from an unsupported Miri operation and skip it when enabled with its own flag. Thoughts?

Miri is basically a rustc backend; which error codes does rustc use?

No idea, though reportedly it's at least possible for it to return an error code other than 0 or 1: rust-lang/rust#51975.

@camelid
Copy link
Member

camelid commented Nov 4, 2021

No idea, though reportedly it's at least possible for it to return an error code other than 0 or 1: rust-lang/rust#51975.

In general, rustc exits with 101 when it panics, just like regular Rust programs.

@RalfJung
Copy link
Member

RalfJung commented Nov 4, 2021

Makes sense, though I do think it'd be possible to have the libtest harness override its behavior when running in Miri if there were a way to communicate this info, maybe by using -Zmiri-panic-on-unsupported. The test harness could identify the panic and determine whether it came from an unsupported Miri operation and skip it when enabled with its own flag. Thoughts?

Yes, we could establish some sort of interaction between Miri and the test harness. AFAIK this is already possible to some extend -- the test harness will catch the panic and continue evaluation, right? So it actually will continue running tests here, I think. See #1807 for the motivation that lead to -Zmiri-panic-on-unsupported; possibly there is some pattern here that we should document.

The basic idea seems to be to pass -Z unstable-options --format json to the test runner, run Miri with -Zmiri-panic-on-unsupported, and then parse the resulting JSON to basically ignore tests that failed due to a panic. Though even without that processing, just MIRIFLAGS=-Zmiri-panic-on-unsupported cargo miri test should already tell you if there is any UB anywhere (which leads to Miri errors) or just unsupported operations (which lead to panics, that the test harness will complain about in its summary).

@RalfJung
Copy link
Member

@kupiakos I wonder if you had the chance to try out the proposals in my last comment? I think MIRIFLAGS=-Zmiri-panic-on-unsupported cargo miri test, possibly in combination with -Z unstable-options --format json, should let you filter out tests that fail due to unsupported FFI and focus on other Miri errors. And this should be much better than different error codes, since you don't have to cfg(not(miri)) all the tests that need FFI.

@RalfJung RalfJung changed the title No easy way to distinguish between Miri identifying UB and Miri being unable to run tests Automatically distinguish between Miri identifying UB and Miri being unable to run tests Dec 16, 2021
@RalfJung RalfJung added the C-support Category: Not necessarily a bug, but someone asking for support label Dec 16, 2021
@RalfJung RalfJung added the A-ux Area: This affects the general user experience label Jan 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ux Area: This affects the general user experience C-support Category: Not necessarily a bug, but someone asking for support
Projects
None yet
Development

No branches or pull requests

3 participants