【发布时间】:2017-03-29 20:05:37
【问题描述】:
今天我在g++6.2 和g++7.0 上花了很多时间trying to understand why this code segfaults,同时愉快地在clang++3.9 上按预期工作(和4.0)。 p>
我将问题简化为85 lines self-contained code snippet,在正常执行时不会出现段错误,但在 UBSAN 下总是报告错误。
问题is reproducible on wandbox,通过使用g++7 编译,启用优化并将-fsanitize=undefined 作为额外标志传递。
这是 UBSAN 报告的内容:
prog.cc: In function 'int main()':
prog.cc:61:49: warning: 'ns#0' is used uninitialized in this function [-Wuninitialized]
([&] { ([&] { n.execute(ns...); })(); })();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
prog.cc:28:10: note: 'ns#0' was declared here
auto execute(TNode& n, TNodes&... ns)
^~~~~~~
prog.cc:30:9: runtime error: member call on null pointer of type 'struct node_then'
g++ 声称 ns#0 在“lambda gibberish”中未初始化(它模拟了原始 sn-p 中的 for_tuple)。现在,发生了一些非常有趣的事情:
-
如果我删除“lambda gibberish”,将 line 61 转换为
n.execute(ns...);然后 UBSAN 停止抱怨。
-
如果我将捕获列表从
[&]更改为[&n, &ns...],UBSAN 也会停止抱怨:([&](auto) { ([&n, &ns...] { n.execute(ns...); })(); })(0);...等等什么?这和
[&]有什么不同?
将上述发现应用于原始代码 sn -p fixes the segfaults。
这是 g++ 错误吗?还是我的代码中有任何未定义的行为?
【问题讨论】:
-
105 行独立代码 sn-p 并不是一个最小的例子。无论如何,内联括号将其转换为最小的,有效的。 :-)
-
我看到你的代码中有很多非常危险的临时文件、副本和盲目引用存储。如果你犯了一个小错误,你就会得到UB。如果它在某个地方没有一个小错误,我会感到震惊;发现它很难,这就是为什么你不应该编写这样的代码。一旦你有了 UB,完全无害的改变会导致事情中断或不中断是正常的。
-
你的 105 行,一连串的开始和等待,然后 - 你是说少一个
then导致它不会产生你的问题?如果不是,它是如何最小的? -
不管怎样,最让我不解的是
[&]改成[&n, &ns...]后问题没有重现。这对我来说是编译器错误的味道,因为我希望这两个捕获列表是等效的。 -
@Arunmu:哎呀——你是对的。我发现bug #71386 看起来与这里的问题有关。
标签: c++ segmentation-fault c++14 undefined-behavior ubsan