【问题标题】:Stack limit and recursive functions堆栈限制和递归函数
【发布时间】:2018-09-24 10:11:38
【问题描述】:

C 程序使用递归来查找图的属性。由于堆栈空间太小,无法处理大图。程序必须重新编码以使用显式堆栈和循环。

递归函数是否应该首先检查输入是否“适合”堆栈空间?

在 linux 内核中是否有一个递归函数必须替换为“显式”递归的示例?

【问题讨论】:

  • 我认为大多数时候几乎不可能检查输入是否适合堆栈,因为输入可能是一个非常复杂的表达式。
  • 在生产环境中,递归保持在最低限度,SO 风险几乎为零。我怀疑 Linux 内核中有很多递归是在 CPU 堆栈上完成的。
  • 什么是“显式递归”
  • @Mulliganaceous “显式递归” 使用显式堆栈和循环实现递归,而不是使用使用进程堆栈的递归函数(隐式)参见stackoverflow.com/questions/3391285/…
  • 我不确定它是否对你有帮助:考虑limiting the recursion depth

标签: c recursion linux-kernel stack stack-overflow


【解决方案1】:

递归函数是否应该检查输入是否“适合”堆栈空间 第一个?

这通常非常困难。当使用不同的编译器或同一编译器的不同版本或使用不同的编译器开关来编译代码时,每个递归调用所需的堆栈内存量可能会有所不同。事实上,函数在不同的调用中可能需要不同数量的堆栈内存,具体取决于其控制流程。

因此,如果您认为存在堆栈溢出的严重风险,则应将递归转换为迭代(可能使用显式堆栈)和/或限制递归/迭代的次数。

在 linux 内核中是否有递归函数具有的示例 替换为“显式”递归?

是的。一个很好的例子是实现符号链接解析的代码。 Prior to Linux 4.2,代码递归如下:

link_path_walk -> nested_symlink -> follow_link -> link_path_walk

link_path_walk 是主要的名称解析功能。如果它检测到一个符号链接,它会调用nested_symlink,然后它可能会递归地调用link_path_walk。为了缓解内核中的堆栈溢出,nested_symlink 执行以下检查:

if (unlikely(current->link_count >= MAX_NESTED_LINKS)) {
    path_put_conditional(path, nd);
    path_put(&nd->path);
    return -ELOOP;
}

每个任务描述符都有一个link_count 字段,每次调用nested_symlink 时都会增加该字段。如果超过一个固定阈值(MAX_NESTED_LINKS 在 Linux 4.1.51 中为 8),则整个操作会以错误终止。

从 Linux 4.2 开始,递归代码变成了带有显式堆栈的迭代代码,阈值放宽到 40。这个article 详细讨论了迭代代码。

【讨论】:

    猜你喜欢
    • 2023-03-27
    • 1970-01-01
    • 2017-09-05
    • 2014-01-17
    • 2018-10-16
    • 2017-09-12
    • 1970-01-01
    • 2017-10-20
    相关资源
    最近更新 更多