Skip to content

Commit 9a738fd

Browse files
committed
rt: Various tweaks to make __morestack unwinding work on linux
When unwinding through __morestack the stack limit in the TLS is invalidated and must be reset. Instead of actually landing at __morestack we're just going to make all our Rust landing pads call upcall_reset_stack_limit, which will find the stack segment that corresponds to the current stack pointer and put the limit in the TLS. Also massively expand the stack segment red zone to make more room for the dynamic linker. Will fix in the future.
1 parent a1b215a commit 9a738fd

File tree

10 files changed

+65
-6
lines changed

10 files changed

+65
-6
lines changed

src/comp/back/upcall.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ type upcalls =
2727
dynastack_free: ValueRef,
2828
alloc_c_stack: ValueRef,
2929
call_shim_on_c_stack: ValueRef,
30-
rust_personality: ValueRef};
30+
rust_personality: ValueRef,
31+
reset_stack_limit: ValueRef};
3132

3233
fn declare_upcalls(targ_cfg: @session::config,
3334
_tn: type_names,
@@ -89,7 +90,8 @@ fn declare_upcalls(targ_cfg: @session::config,
8990
// arguments: void *args, void *fn_ptr
9091
[T_ptr(T_i8()), T_ptr(T_i8())],
9192
int_t),
92-
rust_personality: d("rust_personality", [], T_i32())
93+
rust_personality: d("rust_personality", [], T_i32()),
94+
reset_stack_limit: dv("reset_stack_limit", [])
9395
};
9496
}
9597
//

src/comp/middle/trans.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3904,6 +3904,11 @@ fn trans_landing_pad(bcx: @block_ctxt,
39043904
// The landing pad block is a cleanup
39053905
SetCleanup(bcx, llpad);
39063906

3907+
// Because we may have unwound across a stack boundary, we must call into
3908+
// the runtime to figure out which stack segment we are on and place the
3909+
// stack limit back into the TLS.
3910+
Call(bcx, bcx_ccx(bcx).upcalls.reset_stack_limit, []);
3911+
39073912
// FIXME: This seems like a very naive and redundant way to generate the
39083913
// landing pads, as we're re-generating all in-scope cleanups for each
39093914
// function call. Probably good optimization opportunities here.

src/rt/arch/i386/record_sp.S

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
#if defined(__APPLE__) || defined(_WIN32)
44
#define RECORD_SP _record_sp
5+
#define GET_SP _get_sp
56
#else
67
#define RECORD_SP record_sp
8+
#define GET_SP get_sp
79
#endif
810

911
.globl RECORD_SP
12+
.globl GET_SP
1013

1114
#if defined(__linux__)
1215
RECORD_SP:
@@ -25,3 +28,7 @@ RECORD_SP:
2528
ret
2629
#endif
2730
#endif
31+
32+
GET_SP:
33+
movl %esp, %eax
34+
ret

src/rt/arch/x86_64/morestack.S

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ MORESTACK:
132132

133133
addq $8, %rsp
134134
popq %rbp
135+
#ifdef __linux__
136+
.cfi_restore %rbp
137+
.cfi_def_cfa %rsp, 8
138+
#endif
135139
ret
136140

137141
#if defined(__ELF__)

src/rt/arch/x86_64/record_sp.S

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
#if defined(__APPLE__) || defined(_WIN32)
44
#define RECORD_SP _record_sp
5+
#define GET_SP _get_sp
56
#else
67
#define RECORD_SP record_sp
8+
#define GET_SP get_sp
79
#endif
810

911
.globl RECORD_SP
12+
.globl GET_SP
1013

1114
#if defined(__linux__)
1215
RECORD_SP:
@@ -23,3 +26,7 @@ RECORD_SP:
2326
ret
2427
#endif
2528
#endif
29+
30+
GET_SP:
31+
movq %rsp, %rax
32+
ret

src/rt/rust_task.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
// to the rt, compiler and dynamic linker for running small functions
1919
// FIXME: We want this to be 128 but need to slim the red zone calls down
2020
#ifdef __i386__
21-
#define RED_ZONE_SIZE 2048
21+
#define RED_ZONE_SIZE 65536
2222
#endif
2323

2424
#ifdef __x86_64__
25-
#define RED_ZONE_SIZE 2048
25+
#define RED_ZONE_SIZE 65536
2626
#endif
2727

2828
// Stack size
@@ -613,6 +613,29 @@ rust_task::record_stack_limit() {
613613
"Stack size must be greater than LIMIT_OFFSET");
614614
record_sp(stk->data + LIMIT_OFFSET + RED_ZONE_SIZE);
615615
}
616+
617+
extern "C" uintptr_t get_sp();
618+
619+
/*
620+
Called by landing pads during unwinding to figure out which
621+
stack segment we are currently running on, delete the others,
622+
and record the stack limit (which was not restored when unwinding
623+
through __morestack).
624+
*/
625+
void
626+
rust_task::reset_stack_limit() {
627+
uintptr_t sp = get_sp();
628+
// Not positive these bounds for sp are correct.
629+
// I think that the first possible value for esp on a new
630+
// stack is stk->limit, which points one word in front of
631+
// the first work to be pushed onto a new stack.
632+
while (sp <= (uintptr_t)stk->data || stk->limit < sp) {
633+
del_stk(this, stk);
634+
A(sched, stk != NULL, "Failed to find the current stack");
635+
}
636+
record_stack_limit();
637+
}
638+
616639
//
617640
// Local Variables:
618641
// mode: C++

src/rt/rust_task.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond
200200
void *new_stack(size_t stk_sz, void *args_addr, size_t args_sz);
201201
void del_stack();
202202
void record_stack_limit();
203+
void reset_stack_limit();
203204
};
204205

205206
//

src/rt/rust_upcall.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,15 @@ upcall_del_stack() {
259259
task->del_stack();
260260
}
261261

262+
// Landing pads need to call this to insert the
263+
// correct limit into TLS.
264+
// NB: This must be called on the Rust stack
265+
extern "C" CDECL void
266+
upcall_reset_stack_limit() {
267+
rust_task *task = rust_scheduler::get_task();
268+
task->reset_stack_limit();
269+
}
270+
262271
extern "C" _Unwind_Reason_Code
263272
__gxx_personality_v0(int version,
264273
_Unwind_Action actions,

src/rt/rustrt.def.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ upcall_vec_push
6969
upcall_call_shim_on_c_stack
7070
upcall_new_stack
7171
upcall_del_stack
72+
upcall_reset_stack_limit
7273
asm_call_on_stack
7374
rust_uv_default_loop
7475
rust_uv_loop_new

src/test/run-fail/morestack3.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ resource and_then_get_big_again(_i: @int) {
2525
getbig(i - 1);
2626
}
2727
}
28-
getbig(1000);
28+
getbig(100);
2929
}
3030

3131
fn main() {
3232
rustrt::set_min_stack(256u);
33-
std::task::spawn(1000, getbig_and_fail);
33+
std::task::spawn(100, getbig_and_fail);
3434
}

0 commit comments

Comments
 (0)