about summary refs log tree commit diff
path: root/src/rt/rust_task.cpp
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2013-08-01 21:14:43 -0700
committerBrian Anderson <banderson@mozilla.com>2013-08-03 23:40:25 -0700
commit044fa35bf8ab277d90e12559f4de78e73a404033 (patch)
treebae44de7c6c4758d74a6898b77c882cdffac8a9d /src/rt/rust_task.cpp
parent93432a2c2f244f46c8c60c3988483b20def990b7 (diff)
downloadrust-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.
Diffstat (limited to 'src/rt/rust_task.cpp')
-rw-r--r--src/rt/rust_task.cpp11
1 files changed, 11 insertions, 0 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