Uh oh!
There was an error while loading. Please reload this page.
Prevent compiler stack overflow for deeply recursive code - #55617
Conversation
rust-highfive
commented
Nov 2, 2018
(rust_highfive has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
Uh oh!
There was an error while loading. Please reload this page.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
I'm not sure stacker is necessarily rustc-ready right now, but that doesn't mean that it can't be! Some issues I can think of are:
- It only has support for x86 platforms basically, and only Windows/Mac/Linux. It should be easy enough to "add support" for other platforms by basically doing nothing. Full support could be added over time as necessary
- I don't think
stackerdoes anything with guard pages, but ideally it'd also be sure to allocate guard pages for larger segments to protect agains accidental stack overflow - I'm not entirely sure how well panics and such work? It should be relatively easy to
catch_unwindandresume_unwindthough when necessary (just needs to be done)
These are all pretty minor, but I'd want to be sure to handle them before merging if possible!
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Maybe make this dependent on whether stackeractually works?
There was a problem hiding this comment.
How's that relevant? When stacker doesn't work, these values don't matter, because they don't do anything
There was a problem hiding this comment.
I thought this was the default thread stack size, unrelated to stacker. My bad if that's not the case.
There was a problem hiding this comment.
I'm gonna rename the constant to be clearer about this
There was a problem hiding this comment.
Oh you're right, I was looking at the wrong value. But this change is just for crater as noted by @nagisa in #55617 (comment)
We'll bump it back after crater succeeds
michaelwoerister
commented
Nov 5, 2018
Let's do a perf run. |
bors
commented
Nov 5, 2018
🔒 Merge conflict This pull request and the master branch diverged in a way that cannot be automatically merged. Please rebase on top of the latest master branch, and let the reviewer approve again. How do I rebase?Assuming
You may also read Git Rebasing to Resolve Conflicts by Drew Blessing for a short tutorial. Please avoid the "Resolve conflicts" button on GitHub. It uses Sometimes step 4 will complete without asking for resolution. This is usually due to difference between how Error message |
oli-obk
commented
Nov 6, 2018
@bors try |
bors
commented
Nov 6, 2018
Prevent compiler stack overflow for deeply recursive code
I was unable to write a test that
1. runs in under 1s
2. overflows on my machine without this patch
The following reproduces the issue, but I don't think it's sensible to include a test that takes 30s to compile. We can now easily squash newly appearing overflows by the strategic insertion of calls to `ensure_sufficient_stack`.
```rust
// compile-pass
#![recursion_limit="1000000"]
macro_rules! chain {
(EE $e:expr) => {$e.sin()};
(RECURSE $i:ident $e:expr) => {chain!($i chain!($i chain!($i chain!($i $e))))};
(Z $e:expr) => {chain!(RECURSE EE $e)};
(Y $e:expr) => {chain!(RECURSE Z $e)};
(X $e:expr) => {chain!(RECURSE Y $e)};
(A $e:expr) => {chain!(RECURSE X $e)};
(B $e:expr) => {chain!(RECURSE A $e)};
(C $e:expr) => {chain!(RECURSE B $e)};
// causes overflow on x86_64 linux
// less than 1 second until overflow on test machine
// after overflow has been fixed, takes 30s to compile :/
(D $e:expr) => {chain!(RECURSE C $e)};
(E $e:expr) => {chain!(RECURSE D $e)};
(F $e:expr) => {chain!(RECURSE E $e)};
// more than 10 seconds
(G $e:expr) => {chain!(RECURSE F $e)};
(H $e:expr) => {chain!(RECURSE G $e)};
(I $e:expr) => {chain!(RECURSE H $e)};
(J $e:expr) => {chain!(RECURSE I $e)};
(K $e:expr) => {chain!(RECURSE J $e)};
(L $e:expr) => {chain!(RECURSE L $e)};
}
fn main() {
let x = chain!(D 42.0_f32);
}
```
fixes#55471fixes#41884fixes#40161fixes#34844fixes#32594
cc @alexcrichton@rust-lang/compiler
I looked at all code that checks the recursion limit and inserted stack growth calls where appropriate.bors
commented
Nov 6, 2018
☀️ Test successful - status-travis |
oli-obk
commented
Nov 6, 2018
@rust-timer build 2b10b3d |
rust-timer
commented
Nov 6, 2018
Success: Queued 2b10b3d with parent f90aab7, comparison URL. |
rust-timer
commented
Nov 6, 2018
Finished benchmarking try commit 2b10b3d |
oli-obk
commented
Nov 6, 2018
Improvements for ctfe stress tests (spurious?), regressions up to 3% for everything else except the |
michaelwoerister
commented
Nov 7, 2018
Makes sense that the |
oli-obk
commented
Nov 7, 2018
Well, this is an operation we now run on every single query (not every call, just every evaluation). There are loads of queries. It seems logical that this introduces some regression that we can't get rid of. |
michaelwoerister
commented
Nov 7, 2018
But
|
eddyb
commented
Nov 7, 2018
I feel like the actual stack check shouldn't be noticeable compared to hashing and looking up a key in a hashmap. Maybe we're growing the stack more often than we need to? |
nikic
commented
Nov 7, 2018
Looking at the stacker implementation, a possible issue might be that we're sitting somewhere close to the stack limit and regularly go over it and below it again. This will allocate and deallocate a new stack every time. Maybe retaining the last allocation would help to reduce the performance impact? |
nagisa
commented
Nov 8, 2018
via email
My initial proposal separately mentioned that we should only grow the stack
and never bother redicing its size. I made that call with performance in
mind. I didn't realise stacker was deallocating stack fragments, though now
that I think about it, *that* is the obvious implementation for the stacker
approach. …On Wed, Nov 7, 2018, 19:15 Nikita Popov ***@***.*** wrote:
Looking at the stacker implementation, a possible issue might be that
we're sitting somewhere close to the stack limit and regularly go over it
and below it again. This will allocate and deallocate a new stack every
time. Maybe retaining the last allocation would help to reduce the
performance impact?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#55617 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AApc0ssfA1jZIb2KMI_ZkxHe12s2Eb0yks5usxU-gaJpZM4YL3aW>
.
|
mati865
commented
May 5, 2020
oli-obk
commented
May 6, 2020
on top of your rebase, we also need to bump stacker to 0.1.8, right? |
@oli-obk yes, I had patched |
oli-obk
commented
May 6, 2020
I gave you access to my repo so you can push directly to this PR if you want. |
mati865
commented
May 6, 2020
Done. |
oli-obk
commented
May 6, 2020
Ok, let's give this another shot @bors r=nagisa,oli-obk |
bors
commented
May 6, 2020
📌 Commit 935a05f has been approved by |
bors
commented
May 6, 2020
⌛ Testing commit 935a05f with merge 878cf125ca608577c9980b2c96e26dd1c77c3ad9... |
Dylan-DPC-zz
commented
May 6, 2020
@bors retry (yield) |
bors
commented
May 6, 2020
⌛ Testing commit 935a05f with merge 1e4ad8ae1ae7c74ced296fd2e6380a81a5f6357c... |
Dylan-DPC-zz
commented
May 6, 2020
@bors retry yield |
bors
commented
May 6, 2020
⌛ Testing commit 935a05f with merge 698a0e16dbbb8fa45c5f0dd8c298ad8e98d14f80... |
Dylan-DPC-zz
commented
May 6, 2020
@bors retry yield |
bors
commented
May 6, 2020
⌛ Testing commit 935a05f with merge 18e1bdf136f4f0a269ac64e89c73020ad8b882a6... |
Dylan-DPC-zz
commented
May 6, 2020
@bors retry yield |
bors
commented
May 7, 2020
bors
commented
May 7, 2020
☀️ Test successful - checks-actions, checks-azure |
Mark-Simulacrum
commented
May 8, 2020
cc @XAMPPRocky I tagged this with relnotes-perf but it's not really perf so much as "hey this fixes a longstanding problem, would be cool to mention" |
I was unable to write a test that
The following reproduces the issue, but I don't think it's sensible to include a test that takes 30s to compile. We can now easily squash newly appearing overflows by the strategic insertion of calls to
ensure_sufficient_stack.fixes#55471
fixes#41884
fixes#40161
fixes#34844
fixes#32594
cc @alexcrichton @rust-lang/compiler
I looked at all code that checks the recursion limit and inserted stack growth calls where appropriate.