【发布时间】:2017-06-29 16:28:35
【问题描述】:
在过去的几天里,我一直在调试一个涉及 C++ 中 lambda 的奇怪问题。我已将问题归结为以下症状:
-
this指针在 lambda 中损坏(注意:this总是被复制捕获,因此 lambda 应该有自己的this指针,它指向App对象) -
仅当存在
std::cout打印语句时才会发生,并且在创建 lambda 之前调用。 print 语句可能看起来完全不相关(例如 print "Hello!")。printf()也表现出相同的行为。 - 仅在交叉编译时发生。
- 它可以使用
x86架构的标准编译器正常编译和运行(请参阅example)。 - 如果我在堆上创建 lambda(并将指向它的指针保存在
App对象中),则不会发生错误。 -
如果关闭优化,则不会出现该错误(即,如果我设置了
-O0标志)。当优化设置为-O2时会发生这种情况。
以下是我能想到的导致问题的最简单、可编译的代码示例。
#include <iostream>
#include <functional>
class App {
public:
std::function<void*()> test_;
void Run() {
// Enable this line, ERROR is printed
// Disable this line, app runs o.k.
std::cout << "This print statement causes the bug below!" << std::endl;
test_ = [this] () {
return this;
};
void* returnedThis = test_();
if(returnedThis != this) {
std::cout << "ERROR: 'this' returned from lambda (" << returnedThis
<< ") is NOT the same as 'this' (" << this << ") !?!?!?!?!"
<< std::endl;
} else {
std::cout << "Program run successfully." << std::endl;
}
}
};
int main(void) {
App app;
app.Run();
}
在目标设备上运行时,我得到以下输出:
This print statement causes the bug below!
ERROR: 'this' returned from lambda (0xbec92dd4) is NOT the same as 'this'
(0xbec92c68) !?!?!?!?!
如果我尝试取消引用损坏的this,我通常会遇到分段错误,这就是我最初发现错误的方式。
编译器设置
arm-poky-linux-gnueabi-g++ -march=armv7-a -marm -mfpu=neon -std=c++14 \
-mfloat-abi=hard -mcpu=cortex-a9 \
--sysroot=/home/ghunter/sysroots/cortexa9hf-neon-poky-linux-gnueabi \
-O2 -pipe -g -feliminate-unused-debug-types
链接器设置
arm-poky-linux-gnueabi-ld \
--sysroot=/home/ghunter/sysroots/cortexa9hf-neon-poky-linux-gnueabi \
-Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed
编译器版本
~$ arm-poky-linux-gnueabi-g++ --version
arm-poky-linux-gnueabi-g++ (GCC) 6.2.0
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
这可能是编译器错误吗?
【问题讨论】:
-
仅在存在 std::cout 打印语句时发生 大量 UB 标志(这种情况的成功率约为 100%过去对我来说)对我来说,尝试在 valgrind 下运行你的程序
-
第一条经验法则 - 它永远不是编译器错误,它始终是代码中的 UB。 (不过我发现了一个编译器错误。)你能把变量
test_的声明移到Run的主体中吗?如果是这样,您可以将Run的主体移动到main()中吗? -
如果您将
void* returnedThis = test_();更改为void* returnedThis = static_cast<void*>(this);,您会得到同样的结果吗? -
如果您使用
auto test_ = [this] () { return this; };代替std::function(这样test_是lambda 类型而不是转换为std::function),该错误是否仍然重现? -
@gbmhunter 我开始闻起来像个虫子。至少足以认为打开 GCC 错误报告是合理的。您已经收集了相当多的工作/不工作变体的相关示例,应该可以编写高质量的错误报告并得到确认它是错误或解释为什么不是错误的公平机会(如果就是这样)。如果您确实打开了一个错误,请在问题中添加一个指向它的链接,以便我们跟进。
标签: c++ c++11 lambda arm compiler-bug