authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-07 21:23:51-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-07 21:23:51-07:00
logf69cf930648999cedd0716c6804f46b0c1fbf504
tree6857eaaadf5692b2c0ce6adf97f33c30a437a41a
parentd577654e66e3a69592df2a37817260b59a2a190b

std: start code increases stack size as appropriate on linux

closes #8708

2 files changed, 41 insertions(+), 32 deletions(-)

lib/std/start.zig+41-20
......@@ -297,26 +297,47 @@ fn posixCallMainAndExit() noreturn {
297297 std.os.linux.tls.initStaticTLS();
298298 }
299299
300 // TODO This is disabled because what should we do when linking libc and this code
301 // does not execute? And also it's causing a test failure in stack traces in release modes.
302
303 //// Linux ignores the stack size from the ELF file, and instead always does 8 MiB. A further
304 //// problem is that it uses PROT_GROWSDOWN which prevents stores to addresses too far down
305 //// the stack and requires "probing". So here we allocate our own stack.
306 //const wanted_stack_size = gnu_stack_phdr.p_memsz;
307 //assert(wanted_stack_size % std.mem.page_size == 0);
308 //// Allocate an extra page as the guard page.
309 //const total_size = wanted_stack_size + std.mem.page_size;
310 //const new_stack = std.os.mmap(
311 // null,
312 // total_size,
313 // std.os.PROT_READ | std.os.PROT_WRITE,
314 // std.os.MAP_PRIVATE | std.os.MAP_ANONYMOUS,
315 // -1,
316 // 0,
317 //) catch @panic("out of memory");
318 //std.os.mprotect(new_stack[0..std.mem.page_size], std.os.PROT_NONE) catch {};
319 //std.os.exit(@call(.{.stack = new_stack}, callMainWithArgs, .{argc, argv, envp}));
300 // Linux ignores the stack size from the ELF file, and instead always gives 8 MiB.
301 // Here we look for the stack size in our program headers and tell the kernel,
302 // no, seriously, give me that stack space, I wasn't joking.
303 {
304 var i: usize = 0;
305 var at_phnum: usize = undefined;
306 var at_phdr: usize = undefined;
307 while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
308 switch (auxv[i].a_type) {
309 std.elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val,
310 std.elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val,
311 else => continue,
312 }
313 }
314 const phdrs = (@intToPtr([*]std.elf.Phdr, at_phdr))[0..at_phnum];
315 for (phdrs) |*phdr| {
316 switch (phdr.p_type) {
317 std.elf.PT_GNU_STACK => {
318 const wanted_stack_size = phdr.p_memsz;
319 assert(wanted_stack_size % std.mem.page_size == 0);
320
321 std.os.setrlimit(.STACK, .{
322 .cur = wanted_stack_size,
323 .max = wanted_stack_size,
324 }) catch {
325 // If this is a debug build, it will be useful to find out
326 // why this failed. If it is a release build, we allow the
327 // stack overflow to cause a segmentation fault. Memory safety
328 // is not compromised, however, depending on runtime state,
329 // the application may crash due to provided stack space not
330 // matching the known upper bound.
331 if (builtin.mode == .Debug) {
332 @panic("unable to increase stack size");
333 }
334 };
335 break;
336 },
337 else => {},
338 }
339 }
340 }
320341 }
321342
322343 std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
src/main.zig-12
......@@ -180,18 +180,6 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
180180
181181 defer log_scopes.deinit(gpa);
182182
183 if (@import("builtin").target.os.tag == .linux) {
184 // Linux does not respect the stack size specified in the ELF, so we
185 // have to do this at runtime. TODO move this code to start.zig using
186 // the GNU_STACK program header.
187 std.os.setrlimit(.STACK, .{
188 .cur = 16 * 1024 * 1024,
189 .max = 16 * 1024 * 1024,
190 }) catch |err| {
191 warn("unable to increase stack size to 16 MiB", .{});
192 };
193 }
194
195183 const cmd = args[1];
196184 const cmd_args = args[2..];
197185 if (mem.eql(u8, cmd, "build-exe")) {