【问题标题】:Bash script segfaults on brk()brk() 上的 Bash 脚本段错误
【发布时间】:2017-12-28 16:27:06
【问题描述】:

有人能解释一下为什么这个“无休止的”循环会很快出现段错误吗? 例如,假设我们有这个函数:

#!/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. 这是因为它试图访问内存空间中未映射的区域(通过 brk)而导致的段错误吗?
  2. 如果是,为什么要尝试访问它?
  3. malloc() 在这里会是更好的选择吗?
  4. 如果您对此有任何额外/琐碎的信息,我们将不胜感激。

【问题讨论】:

  • 我猜这与递归中的堆栈损坏有关。

标签: c linux bash malloc brk


【解决方案1】:
  1. brks 不相关。它会出现段错误,因为它耗尽了堆栈空间。如果您使用 ulimit -s 512; ./yourscript 减少可用堆栈,您会发现它崩溃得更快。

  2. 它会占用所有堆栈空间,因为您有一个无限递归函数,而 bash 不进行尾调用优化。

  3. 它已经使用了malloc(或其特定于 bash 的版本)。由于malloc 是一个C 库函数而不是系统调用,它不会出现在strace 中。不过分配的内存没有问题,堆栈空间用完了。

  4. brks 用于存储与无限递归相关的一些无限元数据,但这还不够重要。

    当您有未优化的无限递归时,所有语言中的无限递归函数都会以各种形式发生崩溃。在 Java 中尝试 void foo() { foo(); },或者在 Python 中尝试 def foo(): foo()

【讨论】:

    【解决方案2】:

    看起来您看到的是堆栈不断增长,直到资源耗尽。简而言之,这是一个递归问题。

    查看brk() 调用,您会发现它正在更改进程数据段的结尾。增加程序中断是为进程分配内存,但您没有取之不尽的供应。当你用完时,它会崩溃。

    但是关于你的第三个问题,即使是文档中的注释部分也表明 malloc() 是更好的选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-12
      • 2012-09-27
      • 2012-09-08
      • 2011-06-30
      • 1970-01-01
      • 2011-05-13
      • 2011-02-14
      • 1970-01-01
      相关资源
      最近更新 更多