diff options
| author | Brian Anderson <banderson@mozilla.com> | 2013-08-01 21:14:43 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2013-08-03 23:40:25 -0700 |
| commit | 044fa35bf8ab277d90e12559f4de78e73a404033 (patch) | |
| tree | bae44de7c6c4758d74a6898b77c882cdffac8a9d | |
| parent | 93432a2c2f244f46c8c60c3988483b20def990b7 (diff) | |
| download | rust-044fa35bf8ab277d90e12559f4de78e73a404033.tar.gz rust-044fa35bf8ab277d90e12559f4de78e73a404033.zip | |
rt: Fix a corner-case in unwinding that leads to stack overflow
In some scenarios upcall_rust_stack_limit fails to record the stack limit, leaving it 0, and allowing subsequent Rust code to run into the red zone.
| -rw-r--r-- | src/rt/rust_task.cpp | 11 | ||||
| -rw-r--r-- | src/test/run-pass/unwind-resource.rs | 3 |
2 files changed, 13 insertions, 1 deletions
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index 72979d67eef..2f6b8acb072 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -609,10 +609,21 @@ when unwinding through __morestack). void rust_task::reset_stack_limit() { uintptr_t sp = get_sp(); + bool reseted = false; while (!sp_in_stk_seg(sp, stk)) { + reseted = true; prev_stack(); assert(stk != NULL && "Failed to find the current stack"); } + + // Each call to prev_stack will record the stack limit. If we *didn't* + // call prev_stack then we still need to record it now to catch a corner case: + // the throw to initiate unwinding starts on the C stack while sp limit is 0. + // If we don't set the limit here then the rust code run subsequently will + // will veer into the red zone. Lame! + if (!reseted) { + record_stack_limit(); + } } void diff --git a/src/test/run-pass/unwind-resource.rs b/src/test/run-pass/unwind-resource.rs index a36be079b43..bde90e3726e 100644 --- a/src/test/run-pass/unwind-resource.rs +++ b/src/test/run-pass/unwind-resource.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test +// xfail-fast + extern mod extra; use std::comm::*; |
