Skip to content

Commit 94c389a

Browse files
committed
rt: Add RUST_MAX_STACK env var with 8MB default
Closes #1489
1 parent c00ec5f commit 94c389a

9 files changed

+107
-58
lines changed

src/rt/rust_env.cpp

+16-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// The environment variables that the runtime knows about
99
#define RUST_THREADS "RUST_THREADS"
1010
#define RUST_MIN_STACK "RUST_MIN_STACK"
11+
#define RUST_MAX_STACK "RUST_MAX_STACK"
1112
#define RUST_LOG "RUST_LOG"
1213
#define CHECK_CLAIMS "CHECK_CLAIMS"
1314
#define DETAILED_LEAKS "DETAILED_LEAKS"
@@ -69,15 +70,26 @@ get_num_threads()
6970

7071
static size_t
7172
get_min_stk_size() {
72-
char *stack_size = getenv(RUST_MIN_STACK);
73-
if(stack_size) {
74-
return strtol(stack_size, NULL, 0);
73+
char *minsz = getenv(RUST_MIN_STACK);
74+
if(minsz) {
75+
return strtol(minsz, NULL, 0);
7576
}
7677
else {
7778
return 0x300;
7879
}
7980
}
8081

82+
static size_t
83+
get_max_stk_size() {
84+
char *maxsz = getenv(RUST_MAX_STACK);
85+
if (maxsz) {
86+
return strtol(maxsz, NULL, 0);
87+
}
88+
else {
89+
return 1024*1024*8;
90+
}
91+
}
92+
8193
static char*
8294
copyenv(const char* name) {
8395
char *envvar = getenv(name);
@@ -99,6 +111,7 @@ load_env() {
99111

100112
env->num_sched_threads = (size_t)get_num_threads();
101113
env->min_stack_size = get_min_stk_size();
114+
env->max_stack_size = get_max_stk_size();
102115
env->logspec = copyenv(RUST_LOG);
103116
env->check_claims = getenv(CHECK_CLAIMS) != NULL;
104117
env->detailed_leaks = getenv(DETAILED_LEAKS) != NULL;

src/rt/rust_env.h

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
struct rust_env {
22
size_t num_sched_threads;
33
size_t min_stack_size;
4+
size_t max_stack_size;
45
char* logspec;
56
bool check_claims;
67
bool detailed_leaks;

src/rt/rust_task.cpp

+26-13
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,6 @@ unconfig_valgrind_stack(stk_seg *stk) {
121121
VALGRIND_STACK_DEREGISTER(stk->valgrind_id);
122122
}
123123

124-
static void
125-
free_stk(rust_task *task, stk_seg *stk) {
126-
LOGPTR(task->sched, "freeing stk segment", (uintptr_t)stk);
127-
task->free(stk);
128-
}
129-
130124
static void
131125
add_stack_canary(stk_seg *stk) {
132126
memcpy(stk->data, stack_canary, sizeof(stack_canary));
@@ -139,6 +133,21 @@ check_stack_canary(stk_seg *stk) {
139133
&& "Somebody killed the canary");
140134
}
141135

136+
// The amount of stack in a segment available to Rust code
137+
static size_t
138+
user_stack_size(stk_seg *stk) {
139+
return (size_t)(stk->end
140+
- (uintptr_t)&stk->data[0]
141+
- RED_ZONE_SIZE);
142+
}
143+
144+
static void
145+
free_stk(rust_task *task, stk_seg *stk) {
146+
LOGPTR(task->sched, "freeing stk segment", (uintptr_t)stk);
147+
task->total_stack_sz -= user_stack_size(stk);
148+
task->free(stk);
149+
}
150+
142151
static stk_seg*
143152
new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
144153
{
@@ -152,9 +161,7 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
152161

153162
// Try to reuse an existing stack segment
154163
if (task->stk != NULL && task->stk->prev != NULL) {
155-
size_t prev_sz = (size_t)(task->stk->prev->end
156-
- (uintptr_t)&task->stk->prev->data[0]
157-
- RED_ZONE_SIZE);
164+
size_t prev_sz = user_stack_size(task->stk->prev);
158165
if (min_sz <= prev_sz && requested_sz <= prev_sz) {
159166
LOG(task, mem, "reusing existing stack");
160167
task->stk = task->stk->prev;
@@ -171,14 +178,17 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
171178
// The size of the current stack segment, excluding red zone
172179
size_t current_sz = 0;
173180
if (task->stk != NULL) {
174-
current_sz = (size_t)(task->stk->end
175-
- (uintptr_t)&task->stk->data[0]
176-
- RED_ZONE_SIZE);
181+
current_sz = user_stack_size(task->stk);
177182
}
178183
// The calculated size of the new stack, excluding red zone
179184
size_t rust_stk_sz = get_next_stk_size(sched, task, min_sz,
180185
current_sz, requested_sz);
181186

187+
if (task->total_stack_sz + rust_stk_sz > sched->env->max_stack_size) {
188+
LOG_ERR(task, task, "task %" PRIxPTR " ran out of stack", task);
189+
task->fail();
190+
}
191+
182192
size_t sz = sizeof(stk_seg) + rust_stk_sz + RED_ZONE_SIZE;
183193
stk_seg *stk = (stk_seg *)task->malloc(sz, "stack");
184194
LOGPTR(task->sched, "new stk", (uintptr_t)stk);
@@ -191,6 +201,7 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
191201

192202
task->stk = stk;
193203
config_valgrind_stack(task->stk);
204+
task->total_stack_sz += user_stack_size(stk);
194205
return stk;
195206
}
196207

@@ -222,6 +233,7 @@ del_stk(rust_task *task, stk_seg *stk)
222233
unconfig_valgrind_stack(stk);
223234
if (delete_stack) {
224235
free_stk(task, stk);
236+
A(task->sched, task->total_stack_sz == 0, "Stack size should be 0");
225237
}
226238
}
227239

@@ -249,7 +261,8 @@ rust_task::rust_task(rust_scheduler *sched, rust_task_list *state,
249261
killed(false),
250262
propagate_failure(true),
251263
dynastack(this),
252-
cc_counter(0)
264+
cc_counter(0),
265+
total_stack_sz(0)
253266
{
254267
LOGPTR(sched, "new task", (uintptr_t)this);
255268
DLOG(sched, task, "sizeof(task) = %d (0x%x)", sizeof *this, sizeof *this);

src/rt/rust_task.h

+3
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ rust_task : public kernel_owned<rust_task>, rust_cond
126126

127127
debug::task_debug_info debug;
128128

129+
// The amount of stack we're using, excluding red zones
130+
size_t total_stack_sz;
131+
129132
// Only a pointer to 'name' is kept, so it must live as long as this task.
130133
rust_task(rust_scheduler *sched,
131134
rust_task_list *state,
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// error-pattern:ran out of stack
2+
3+
// Test that the task fails after hiting the recursion limit
4+
5+
fn main() {
6+
main();
7+
}

src/test/run-pass/morestack2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ fn getbig(i: int) -> int {
1010
}
1111

1212
fn main() {
13-
getbig(100000);
13+
getbig(10000);
1414
}

src/test/run-pass/morestack3.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@ fn getbig(a0: int,
3737
}
3838

3939
fn main() {
40-
let a = 100000;
40+
let a = 10000;
4141
getbig(a, a+1, a+2, a+3, a+4, a+5, a+6, a+7, a+8, a+9);
4242
}

src/test/run-pass/morestack4.rs

+40-40
Original file line numberDiff line numberDiff line change
@@ -53,45 +53,45 @@ fn getbig(i: biggy) {
5353

5454
fn main() {
5555
getbig({
56-
a00: 100000u64,
57-
a01: 100000u64,
58-
a02: 100000u64,
59-
a03: 100000u64,
60-
a04: 100000u64,
61-
a05: 100000u64,
62-
a06: 100000u64,
63-
a07: 100000u64,
64-
a08: 100000u64,
65-
a09: 100000u64,
66-
a10: 100000u64,
67-
a11: 100000u64,
68-
a12: 100000u64,
69-
a13: 100000u64,
70-
a14: 100000u64,
71-
a15: 100000u64,
72-
a16: 100000u64,
73-
a17: 100000u64,
74-
a18: 100000u64,
75-
a19: 100000u64,
76-
a20: 100000u64,
77-
a21: 100000u64,
78-
a22: 100000u64,
79-
a23: 100000u64,
80-
a24: 100000u64,
81-
a25: 100000u64,
82-
a26: 100000u64,
83-
a27: 100000u64,
84-
a28: 100000u64,
85-
a29: 100000u64,
86-
a30: 100000u64,
87-
a31: 100000u64,
88-
a32: 100000u64,
89-
a33: 100000u64,
90-
a34: 100000u64,
91-
a35: 100000u64,
92-
a36: 100000u64,
93-
a37: 100000u64,
94-
a38: 100000u64,
95-
a39: 100000u64,
56+
a00: 10000u64,
57+
a01: 10000u64,
58+
a02: 10000u64,
59+
a03: 10000u64,
60+
a04: 10000u64,
61+
a05: 10000u64,
62+
a06: 10000u64,
63+
a07: 10000u64,
64+
a08: 10000u64,
65+
a09: 10000u64,
66+
a10: 10000u64,
67+
a11: 10000u64,
68+
a12: 10000u64,
69+
a13: 10000u64,
70+
a14: 10000u64,
71+
a15: 10000u64,
72+
a16: 10000u64,
73+
a17: 10000u64,
74+
a18: 10000u64,
75+
a19: 10000u64,
76+
a20: 10000u64,
77+
a21: 10000u64,
78+
a22: 10000u64,
79+
a23: 10000u64,
80+
a24: 10000u64,
81+
a25: 10000u64,
82+
a26: 10000u64,
83+
a27: 10000u64,
84+
a28: 10000u64,
85+
a29: 10000u64,
86+
a30: 10000u64,
87+
a31: 10000u64,
88+
a32: 10000u64,
89+
a33: 10000u64,
90+
a34: 10000u64,
91+
a35: 10000u64,
92+
a36: 10000u64,
93+
a37: 10000u64,
94+
a38: 10000u64,
95+
a39: 10000u64,
9696
});
9797
}
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// error-pattern:ran out of stack
2+
3+
// Test that the task fails after hiting the recursion limit, but
4+
// that it doesn't bring down the whole proc
5+
6+
fn main() {
7+
task::spawn {||
8+
task::unsupervise();
9+
fn f() { f() };
10+
f();
11+
};
12+
}

0 commit comments

Comments
 (0)