Сегменты ошибок Bash на brk()

Может кто-нибудь объяснить, почему этот "бесконечный" цикл segfaults быстро? Например, допустим, у нас есть эта функция:

#!/bin/bash

foo() {
  foo 
}; foo

Это происходит через 8-10 секунд. Изучая через strace, мы видим много вызовов brk():

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

Мои вопросы:

  1. это segfaulting, потому что он пытается получить доступ к не отображенной области в пространстве памяти (через brk)?
  2. Если да, то почему он пытается получить к нему доступ?
  3. Будет ли malloc() лучшим выбором здесь?
  4. Если у вас есть какая-либо дополнительная / пустяковая информация по этому вопросу, это будет оценено.

2 ответа

Решение
  1. brkс не связаны. Это segfaults, потому что ему не хватает места в стеке. Если вы уменьшите доступный стек с ulimit -s 512; ./yourscript вы увидите, что он падает намного быстрее.

  2. Он поглощает все пространство стека, потому что у вас бесконечно рекурсивная функция, а bash не выполняет оптимизацию хвостовых вызовов.

  3. Он уже использует malloc (или его конкретная версия bash). поскольку malloc функция библиотеки C, а не системный вызов, она не отображается в strace, Однако с распределенной памятью проблем нет, ей не хватает места в стеке.

  4. brkОни используются для хранения некоторых бесконечных метаданных, связанных с вашей бесконечной рекурсией, но этого недостаточно, чтобы иметь значение.

    Сбои в бесконечно рекурсивных функциях происходят в различных формах на всех языках, когда у вас есть неограниченная рекурсия, которая не оптимизирована. Пытаться void foo() { foo(); } на Java или def foo(): foo() в Python.

Похоже, то, что вы видите, - это стек, растущий до истощения ресурсов. Короче говоря, это проблема рекурсии.

Посмотрите на вызов brk(), и вы увидите, что он меняет конец сегмента данных процесса. Увеличение разрыва программы - это выделение памяти для процесса, но у вас нет неиссякаемого запаса. Когда у вас кончается, он падает.

Но что касается вашего третьего вопроса, даже раздел примечаний в документации предполагает, что malloc() - лучший выбор.

Другие вопросы по тегам