【问题标题】:Why do all C++ compilers crash or hang from this code?为什么所有 C++ 编译器都会在这段代码中崩溃或挂起?
【发布时间】:2020-02-20 21:45:39
【问题描述】:

以下代码在由我测试过的每个 C++ 编译器编译时崩溃或挂起,直到内存耗尽:

#include <tuple>

template<class... Ts>
auto f(Ts... ts){
  return f(std::make_tuple(ts...)); 
}

auto a = f();

在各种版本的 GCC、Clang、MSVC、icc、ELLCC 上测试:https://godbolt.org/z/cwqiZK


我的问题是,为什么这些编译器实现的模板深度限制或类似的安全措施没有发现这一点?我发现了一些导致编译器挂起的代码示例like this old example,但似乎我能找到的所有问题都已得到修复,因为它已成为限制模板实例化深度的标准。

我应该注意,这不是 make_tuple 独有的,适用于 tieforward_as_tuple... 等。


作为警告,如果您尝试在本地编译它,请务必使用ulimit 之类的内容,以确保编译器不会耗尽您的内存。在玩这个时,我不得不硬重启几次。

【问题讨论】:

  • 它们确实有深度限制,但在这种情况下,所需的内存可能会随着深度的二次方增长,因为您将拥有 std::tuple<:tuple>> (N 层) 在第 N 级。
  • " 如果您尝试在本地编译,请务必使用类似 ulimit" 或手动使用 (gcc) 标志 -ftemplate-depth=X Demo
  • 这有点像为什么编译器不解决停机问题。
  • @Barry,是吗?在这种情况下,提供了很多信息来知道停止是不可能的。
  • @JeffreyCash:“是吗?”是的。在许多情况下,您可以确定是否可以在多种语言中停止,但这并不意味着编译器应该尝试这样做。仅仅因为你可以看到无限递归并不意味着我们应该让编译器尝试做同样的事情。

标签: c++ templates c++14 c++17


【解决方案1】:

GCC 没有实现所有可能的可变参数函数模板递归检测方法(或者可能没有?),这可能是由于 cmets 中提出的问题的变化。

OP 示例看起来与 2014 年未解决的 GCC bug 59914 非常相似(相同?)。看起来防止这类错误,或者实际上——防止这类错误在开发人员的工作站上爆炸——并不是 GCC 开发人员的首要任务。顺便说一句 - 错误报告中报告的示例程序比 OP 更快地滥用内存:使用 800MB 数据限制,我可以让 OP 执行超过 150 次模板实例化,而错误报告中的程序在不到 20 次后内存不足.

这两个程序也会使 clang 崩溃,所以我猜 clang 开发者的优先级相似。

【讨论】:

    猜你喜欢
    • 2014-08-12
    • 2018-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-16
    • 2010-11-28
    相关资源
    最近更新 更多