Skip to content
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

Increasing stack size limit results in inconsistent behavior, stack overflow #43879

Closed
ccope opened this issue Aug 15, 2017 · 3 comments
Closed
Labels
C-bug Category: This is a bug. I-needs-decision Issue: In need of a decision. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@ccope
Copy link

ccope commented Aug 15, 2017

I'm writing some toy programs to learn rust and encountered some strange behavior when changing stack size limits.

I tried building and running this code: https://github.com/ccope/oom-rs

I expected to see this happen: Printing out the changed stack size limit, followed by the test strings.

Instead, this happened:

Meta

Ubuntu 16.04, kernel 4.10.0-32-generic

rustc --version --verbose:

1.19.0:

rustc 1.19.0 (0ade33941 2017-07-17)
binary: rustc
commit-hash: 0ade339411587887bf01bcfa2e9ae4414c8900d4
commit-date: 2017-07-17
host: x86_64-unknown-linux-gnu
release: 1.19.0
LLVM version: 4.0

1.21.0:

rustc 1.21.0-nightly (df511d554 2017-08-14)
binary: rustc
commit-hash: df511d5548ebb7f971abcd3a5283cb1d37b64596
commit-date: 2017-08-14
host: x86_64-unknown-linux-gnu
release: 1.21.0-nightly
LLVM version: 4.0
@ccope
Copy link
Author

ccope commented Aug 15, 2017

Fired up GDB, and the segfault happened in compiler_builtins::probestack::__rust_probestack () at /checkout/src/rustc/compiler_builtins_shim/../../libcompiler_builtins/src/probestack.rs:55 (in the nightly rust build). Then I set a breakpoint on that function and was able to get a backtrace that led me to std::rt::lang_start() and sys::thread::guard::init(). Looking at this code, I wouldn't expect setrlimit(RLIMIT_STACK) to ever work inside main() because the guard pages will already be present in the middle of the address space.

@ccope ccope changed the title Stack overflow when using release build, but not debug Increasing stack size limit results in inconsistent behavior, stack overflow Aug 15, 2017
@Mark-Simulacrum Mark-Simulacrum added C-enhancement Category: An issue proposing an enhancement or a PR with one. C-bug Category: This is a bug. I-needs-decision Issue: In need of a decision. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. and removed C-enhancement Category: An issue proposing an enhancement or a PR with one. labels Aug 20, 2017
@Mark-Simulacrum
Copy link
Member

cc @alexcrichton

@alexcrichton
Copy link
Member

I believe this is all working as intended so I'm going to close this, but thanks for the report!

In 1.20.0 Rust gained support for "stack probes" which is the __rust_probestack function that you see. A stack probe is basically just a function prologue which touches each page of a stack if the stack size is greater than a page (which it is in this case an the stack-allocated bfa array. Note that with the addition of these stack probes it also necessitated the removal of Rust's main-thread guard page on Linux due to a variety of reasons, the tl;dr; of which being that it's already taken care of.

So what's happening here is:

  • 1.19 debug mode - There's no stack probes. The main thread has a Rust-allocated guard page, however. I believe what's happening is that you're hitting this guard page (naturally w/ the huge array) and the runtime is misdiagnosing the segfault, not detecting a stack overflow and printing out something nice.
  • 1.19 release mode - The huge_tracts_of_land function probably gets inlined into the main function, which makes it hit the guard page and unallocated memory even faster. What's probaby happening is the main function completely jumps over the guard page, and because the stack is too big when you're calling println-related functions it's just hitting random unmapped memory below the guard page.
  • 1.21 debug mode - there's stack probes enabled here but notably also there's no main thread guard page allocated by Rust. This means that everything works as expected as Rust touches the stack pages and finds that the setrlimit made room for Linux to allocate all of them.
  • 1.21 release mode - like in 1.19 the huge_tracts_of_land function is likely inlined, making the main stack way bigger than it should be, triggering a segfault in the probestack function as it touches each page of the stack (and eventually hitting an unmapped page). In this case the runtime correctly diagnoses the segfault as a stack overflow.

In any case I don't think there's anything more to do here. You can get the example working in debug/release mode on 1.20+ with the #[inline(never)] attribute on the huge_tracts_of_land function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. I-needs-decision Issue: In need of a decision. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants