-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Support allocation failures when interpreting MIR #86255
Conversation
Some changes occured to the CTFE / Miri engine cc @rust-lang/miri Some changes occured to the CTFE / Miri engine cc @rust-lang/miri |
r? @varkor (rust-highfive has picked a reviewer for you, use r? to override) |
The original plan we had for having a memory limit in Miri was to make this a configurable limit. The other two limits (stack size, execution steps) are completely controlled by the interpreter. The idea is that interpretation should be completely deterministic and repeatable. This new error, however, depends on arbitrary factors from the environment: the same evaluation can sometimes succeed, and sometimes fail with |
We kind of do have precedent. Consider |
r? @oli-obk |
Maybe? I don't know the invariants of the query system well enough. But this can lead to the same CTFE query having different results in different crates. |
oh right. There's no precedent for that. Maybe this should be a fatal error reported directly at the problematic site instead of it being a regular CTFE error? So the query is never left, but instead the compilation is aborted. not sure how to proceed here. cc @rust-lang/compiler It is very easy to make CTFE run out of RAM, thus crashing rustc. Specifically for CTFE we could catch these out of memory situations and report a proper error, but we're unsure of the implications. |
Yeah, that does seem like it could lead to all sorts of issues. From a very quick glance at the PR, it looks like allocation failures in CTFE still result in compilation failing, just with a nicer error message. If compilation still fails, then this seems ok. Are there cases where CTFE will fail but compilation will still succeed? |
Not all CTFE failures are hard errors (yet). So with We could probably do something similar to #86194, and make all resource exhaustion failures always hard errors. |
I'm wondering if, even with a hard error, the query system + incremental compilation can get "stuck". We aren't tracking resource exhaustion as an input to the query system, so the query will stay green and not get reevaluated, but loaded from the cache. You may have to remove your cache or modify the right piece of code to get the system "unstuck". |
I've made allocation failures a hard error, and it appears that recompiling with more memory available does work, and that the error doesn't get cached, even when forcing incremental compilation with Note that is a lot easier to test this with this diff to make it possible to simulate zero-memory conditions: diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 7405a70d39a..71d09e16ec4 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -125,6 +125,9 @@ pub fn from_bytes_byte_aligned_immutable<'a>(slice: impl Into<Cow<'a, [u8]>>) ->
/// Try to create an Allocation of `size` bytes, failing if there is not enough memory
/// available to the compiler to do so.
pub fn uninit(size: Size, align: Align) -> InterpResult<'static, Self> {
+ if std::env::var(std::ffi::OsStr::new("RUSTC_ALWAYS_FAIL_MIRI_ALLOC")).is_ok() {
+ Err(InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted))?;
+ }
let mut bytes = Vec::new();
bytes.try_reserve(size.bytes_usize()).map_err(|_| { Also note that hard errors currently give a confusing and wrong error message, since there is no differentiation between hard and soft errors in the message generation (EDIT: I opened a PR to fix this: #86340):
|
That's what I would expect. We only write to the incremental cache when the compilation succeeds so as long compilation always fails eventually when there is an allocation failure, there shouldn't be an issue with the incremental system. |
☔ The latest upstream changes (presumably #86291) made this pull request unmergeable. Please resolve the merge conflicts. |
…=RalfJung Use better error message for hard errors in CTFE I noticed this while working on rust-lang#86255: currently the same message is used for hard errors and soft errors in CTFE. This changes the error messages to make hard errors use a message that indicates the reality of the situation correctly, since usage of the constant is never allowed when there was a hard error evaluating it. This doesn't affect the behaviour of these error messages, only the content. This changes the error logic to check if the error should be hard or soft where it is generated, instead of where it is emitted, to allow this distinction in error messages.
☔ The latest upstream changes (presumably #86399) made this pull request unmergeable. Please resolve the merge conflicts. |
@bors r+ |
📌 Commit 72c38905ce940f3543d9067c5398b3670f1ba01f has been approved by |
Delaying a ICE is a great idea, I've gone ahead and implemented it.
This is already done: rust/compiler/rustc_mir/src/transform/const_prop.rs Lines 40 to 43 in 868c702
|
Great! Then making allocation panic immediately (ruling out |
Co-authored-by: Ralf Jung <post@ralfj.de>
Thanks for sticking with me through all these rounds of review. :) |
📌 Commit d83c46f has been approved by |
☀️ Test successful - checks-actions |
Tested on commit rust-lang/rust@39e20f1. Direct link to PR: <rust-lang/rust#86255> 💔 miri on windows: test-pass → build-fail (cc @RalfJung @oli-obk @eddyb). 💔 miri on linux: test-pass → build-fail (cc @RalfJung @oli-obk @eddyb).
Make work with latest rustc Cc rust-lang/rust#86863, which was caused by PR rust-lang/rust#86255.
…shtriplett Use zeroed allocations in the mir interpreter instead eagerly touching the memory rust-lang#86255 introduced a 30% regression in [page faults](https://perf.rust-lang.org/compare.html?start=64ae15ddd3f3cca7036ab2b2f3a6b130b62af4da&end=39e20f1ae5f13451eb35247808d6a2527cb7d060&stat=faults ) and a 3% regression in [max-rss](https://perf.rust-lang.org/index.html?start=2021-07-01&end=&absolute=false&stat=max-rss) in the ctfe-stress benchmarks. That's most likely happened because it separated allocation from initialization of the vec which defeats the zero-optimization. Currently there's no allocation API that is fallible, zeroing and returns a slice, so this PR introduces one and then uses that to solve the problem. In principle `vec.resize(len, 0)` could be optimized to use `alloc::grow_zeroed` where appropriate but that would require new specializations and new plumbing in `RawVec`.
This closes #79601 by handling the case where memory allocation fails during MIR interpretation, and translates that failure into an
InterpError
. The error message is "tried to allocate more memory than available to compiler" to make it clear that the memory shortage is happening at compile-time by the compiler itself, and that it is not a runtime issue.Now that memory allocation can fail, it would be neat if Miri could simulate low-memory devices to make it easy to see how much memory a Rust program needs.
Note that this breaks Miri because it assumes that allocation can never fail.