| ... | @@ -297,26 +297,47 @@ fn posixCallMainAndExit() noreturn { | ... | @@ -297,26 +297,47 @@ fn posixCallMainAndExit() noreturn { |
| 297 | std.os.linux.tls.initStaticTLS(); | 297 | std.os.linux.tls.initStaticTLS(); |
| 298 | } | 298 | } |
| 299 | | 299 | |
| 300 | // TODO This is disabled because what should we do when linking libc and this code | 300 | // Linux ignores the stack size from the ELF file, and instead always gives 8 MiB. |
| 301 | // does not execute? And also it's causing a test failure in stack traces in release modes. | 301 | // Here we look for the stack size in our program headers and tell the kernel, |
| 302 | | 302 | // no, seriously, give me that stack space, I wasn't joking. |
| 303 | //// Linux ignores the stack size from the ELF file, and instead always does 8 MiB. A further | 303 | { |
| 304 | //// problem is that it uses PROT_GROWSDOWN which prevents stores to addresses too far down | 304 | var i: usize = 0; |
| 305 | //// the stack and requires "probing". So here we allocate our own stack. | 305 | var at_phnum: usize = undefined; |
| 306 | //const wanted_stack_size = gnu_stack_phdr.p_memsz; | 306 | var at_phdr: usize = undefined; |
| 307 | //assert(wanted_stack_size % std.mem.page_size == 0); | 307 | while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) { |
| 308 | //// Allocate an extra page as the guard page. | 308 | switch (auxv[i].a_type) { |
| 309 | //const total_size = wanted_stack_size + std.mem.page_size; | 309 | std.elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, |
| 310 | //const new_stack = std.os.mmap( | 310 | std.elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, |
| 311 | // null, | 311 | else => continue, |
| 312 | // total_size, | 312 | } |
| 313 | // std.os.PROT_READ | std.os.PROT_WRITE, | 313 | } |
| 314 | // std.os.MAP_PRIVATE | std.os.MAP_ANONYMOUS, | 314 | const phdrs = (@intToPtr([*]std.elf.Phdr, at_phdr))[0..at_phnum]; |
| 315 | // -1, | 315 | for (phdrs) |*phdr| { |
| 316 | // 0, | 316 | switch (phdr.p_type) { |
| 317 | //) catch @panic("out of memory"); | 317 | std.elf.PT_GNU_STACK => { |
| 318 | //std.os.mprotect(new_stack[0..std.mem.page_size], std.os.PROT_NONE) catch {}; | 318 | const wanted_stack_size = phdr.p_memsz; |
| 319 | //std.os.exit(@call(.{.stack = new_stack}, callMainWithArgs, .{argc, argv, envp})); | 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 | } |
| 320 | } | 341 | } |
| 321 | | 342 | |
| 322 | std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp })); | 343 | std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp })); |