clinuxbashmallocbrk

Bash script segfaults on brk()


can someone explain why this "endless" loop segfaults quickly? For example, let's say we have this function:

#!/bin/bash

foo() {
  foo 
}; foo

This segfaults after 8-10 seconds. Examining via strace, we can see a lot of brk() calls:

brk(0x2e11000)                          = 0x2e11000
brk(0x2e12000)                          = 0x2e12000
brk(0x2e13000)                          = 0x2e13000
brk(0x2e14000)                          = 0x2e14000
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x7ffcddf5ff68} ---
+++ killed by SIGSEGV +++
Segmentation fault

My questions are:

  1. is this segfaulting because it's trying to access an unmapped region in memory space (via brk)?
  2. If yes, why is it trying to access it?
  3. Would malloc() be a better choice here?
  4. If you have any extra/trivia information on this, it would be appreciated.

Solution

    1. The brks are not related. It segfaults because it runs out of stack space. If you reduce the available stack with ulimit -s 512; ./yourscript you'll see that it crashes much quicker.

    2. It gobbles up all stack space because you have an infinitely recursive function and bash does not do tail call optimization.

    3. It already uses malloc (or a bash specific version thereof). Since malloc is a C library function and not a syscall, it does not show up in strace. There is no problem with allocated memory though, it's running out of stack space.

    4. The brks are used to store some of the infinite metadata associated with your infinite recursion, but it's not enough to matter.

      Crashes in infinitely recursive functions happens in various forms in all languages when you have unbounded recursion that isn't optimized. Try void foo() { foo(); } in Java, or def foo(): foo() in Python.