【问题标题】:"this" captured by lambda is incorrect. GCC compiler bug?lambda 捕获的“this”不正确。 GCC编译器错误?
【发布时间】: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&lt;void*&gt;(this);,您会得到同样的结果吗?
  • 如果您使用auto test_ = [this] () { return this; }; 代替std::function(这样test_ 是lambda 类型而不是转换为std::function),该错误是否仍然重现?
  • @gbmhunter 我开始闻起来像个虫子。至少足以认为打开 GCC 错误报告是合理的。您已经收集了相当多的工作/不工作变体的相关示例,应该可以编写高质量的错误报告并得到确认它是错误或解释为什么不是错误的公平机会(如果就是这样)。如果您确实打开了一个错误,请在问题中添加一个指向它的链接,以便我们跟进。

标签: c++ c++11 lambda arm compiler-bug


【解决方案1】:

这似乎是 gcc 6.2 中的编译器错误,请参阅:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77686

解决方法:

  • 使用 -fno-schedule-insns2 标志(正如 gbmhunter 所指出的,请参阅下面的评论)。
  • 不要使用-O2 或更高的优化。

【讨论】:

  • 谢谢!这似乎是错误。如链接邮件列表中所述,添加标志-fno-schedule-insns2(禁用指令调度)也可以解决此问题。这使您可以将优化级别保持在 -O2-O3(但请注意,-fno-schedule-insns2 可能仍会影响代码的速度)。
【解决方案2】:

听起来像以下编译器错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77933(仅影响使用 O1 优化或更高优化生成的代码)。

【讨论】:

  • 感谢您的信息!我将在接下来的 3 天左右对此进行调查以确认,如果是,请接受此答案:-)
  • 我实际上没有时间进行全面验证(即仔细检查汇编代码并与记录的错误进行比较)。但是因为它完全符合这个错误描述(例如,只发生在优化 O1 或更高版本,在旧版本的 GCC 上,并破坏堆栈)我接受这个答案。谢谢!
  • 我真的不认为它是gcc.gnu.org/bugzilla/show_bug.cgi?id=77933 as.... 1.我已经应用了补丁,它仍然失败。 2. 那个错误在 __builtin_return_address()... 我看不到这个问题附近的任何地方。
  • @JohnCarter 是的,可以抓住。查看 Philipp Huppertz 的回答,我相信他找到了正确的错误。
猜你喜欢
  • 2015-02-12
  • 2021-07-24
  • 1970-01-01
  • 2021-12-19
  • 2016-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多