-
Notifications
You must be signed in to change notification settings - Fork 353
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
Miri disables debug_assertions
in std, and so misses some library UB it could be reporting
#2497
Comments
You have already listed the downsides which explain why at least currently, I don't think Miri should enable debug assertions in the stdlib. To add to that: the main goal and primary purpose of Miri is to detect language UB. If we can also get some library UB, sure, but (a) it should always be clear which is which, and (b) that should not come at the expense of its ability to detect language UB. (So, losing notable performance due to this is bad. Miri is already so slow that some code cannot reasonably be tested with Miri.) Once you have established with Miri that there is no language UB, I think there are better ways than Miri to detect library UB -- namely, you can now just run regular compiled code with debug assertions, and since there is no language UB, you know that nothing weird will happen and the library UB detection is in full effect. I know it is currently hard to run the standard library with debug assertions, and Miri already compiles its own standard library so it is easy for Miri to enable debug assertions, but that does not make Miri the right tool for "running the standard library with debug assertions". Instead we should work on making it easier to run code against a standard library built with debug assertions. Honestly that's not even that hard to do... maybe I can spend a bit of time on that, a |
The precipitating context for this is: fn main() {
let _foo = unsafe { *[()].get_unchecked(1) };
}
(OP runs the code under Miri, no error) confusion ensues, someone asks:
So I think we have two problems here. Miri is seen as the tool to find UB, and yet it is opting out of UB checks. So I think we have a user experience problem here because we betray the user's expectations. I just ran the benchmarks on my Secondly, I'm concerned that this case maybe shouldn't be UB. I think |
Yeah I highly doubt this will ever be language UB. I do agree we need to get better at distinguishing language UB and library UB. To an extent we currently use that distinction to hide the fact that language UB has not been precisely specified yet. That's not great, of course, but also not something we can fix until we do have a more precise spec of language UB. |
rust-lang/rust#101079 would bring those regressions down to between 0% and 10%. I could make the regressions smaller, but I'm trying to balance against complicating the standard library code. It's not easy to make unoptimized code faster. |
I was also concerned about checks somewhere inside data structures, such as HashMap or BTreeMap. If there are debug assertions there are check data structure invariants, those might be quite expensive to check in Miri. |
See https://github.com/RalfJung/cargo-careful for a nice way to get a standard library with debug assertions. :) |
In rust-lang/rust#104726 @the8472 got surprised that Miri did not catch library UB. But I still think we don't want all stdlib debug assertions in Miri. The stdlib contains two kinds of debug assertions:
We don't want the second kind in Miri. Maybe we don't even want them in cargo-careful? Looks like we want another macro that's more like Cc @thomcc |
My case is invalid. Miri wouldn't have caught this and neither would have running std tests with debug asserts because the issue is data-dependent and we didn't have a test case covering it. |
debug_assertions
, and so misses some library UB it could be reportingdebug_assertions
in std, and so misses some library UB it could be reporting
This is fixed by rust-lang/rust#121662: the library UB checks in the stdlib are now controlled by whether the final binary crate is run with |
Miri should not disable
debug_assertions
in std (it should in fact explicitly enable them) to improve the detection of bugs in programs, even when they are not language level UB, "only" library UB.std has several additional library invariants that are not language level UB, for example
Vec
's len being less than or equal to its capacity,slice::get_unchecked
needing an index that is in bounds in element count not just bytes (the case where the resulting byte index is out of bounds is handled by other language rules),CStr::from_bytes_with_nul_unchecked
having a trailing null byte and no interior null bytes, andString
containing UTF-8 bytes. Some of these conditions are checked by std using debug assertions, specifically a macro that whendebug_assertions
are enabled,abort
s when the condition fails. Whendebug_assertions
are disabled, it conditionally compiles out to a no-op. Currently Miri disablesdebug_assertions
explicitly, noting that it helps performance. I know nothing about this performance nor have I tested performance with or withoutdebug_assertions
.As a concrete example, the following code:
passes miri with no warnings or errors currently (nightly 2022-08-18), however, it fails to complete execution successfully under a
-Zbuild-std
withdebug_assertions
enabled, aborting due to an illegal instruction caused by theabort
.Modifying Miri to enable the flag produces an error, which, even though it's not optimal, is much better than nothing. This error could also be improved with cooperation from std to improve the debug checks.
This, with no other modifications, raises an error, points to the code the user passed, mentions
assert_unsafe_precondition
, and has the condition that failed, which should tell the user to check that they're satisfying the unsafe conditions of the function they're calling. This is a sufficient, but not ideal error.std could also benefit from an additional pass over unsafe conditions for debug checks. Currently most of the checks are on pointer-like operations. The
Vec
example given above, andStrings
's UTF-8 bytes and several other cases of library-only UB are not checked even in debug mode. This would have even more benefit if Miri also ran those checks by enablingdebug_assertions
.I would be willing to add these assertions and improve the output from the failure of these checks under Miri.
Downsides
Running debug assertions is running more code, which inherently will have some cost.
Several debug assertions check things that Miri would already check via language UB, such as the
slice::get_unchecked
case but for aT
that is not zero sized. Importantly, in these cases that Miri would have already checked, the error gets worse since it's now an abort. (!!this is really bad!!)I believe that there could be a workaround to have certain language level UB not be asserted on if it would already be checked in Miri, but it would be more complicated, involve manually determining whether an unsafe condition causes language or library UB, and being conservative with assertions if it could be both.
The text was updated successfully, but these errors were encountered: