首页 > 解决方案 > 给定一个包含 lambda 函数的调用堆栈,如何确定其来源?

问题描述

假设您有一些代码推送到这样的队列中:

template <typename T>
void submitJobToPool(T callable)
{
    someJobQueue.push(callable)
}

...后来:

template <typename T>
void runJobFromPool(T callable)
{
    auto job = someJobQueue.pop();
    job();
}

现在假设代码由于job()调用内部的一些错误而崩溃。如果提交的作业是普通函数,调用堆栈可能如下所示:

void myFunction()     0x345678901
void runJobFromPool() 0x234567890
int main(int, char**) 0x123456789

很容易看出是什么函数在这里崩溃了。如果它是一个仿函数,它会很相似,但operator()在某处有一个(忽略内联)。但是,对于 lambda...

void lambda_a7009ccf8810b62b59083b4c1779e569() 0x345678901
void runJobFromPool()                          0x234567890
int main(int, char**)                          0x123456789

这不是那么容易调试。如果发生时附加了调试器,或者有可用的核心转储,则该信息可用于派生哪个 lambda 崩溃,但该信息并不总是可用。据我所知,拆卸是确定由此而崩溃的少数几种方法之一。

我必须使它变得更好的想法是:

  1. 使用addr2line平台支持的工具。这有时有效,有时无效。
  2. 将所有 lambda 封装在函子中(至少可以说并不理想)。
  3. 不使用 lambdas(同样,不理想)。
  4. 使用编译器扩展为 lambda 赋予更有意义的名称/添加调试信息。

第四个选项听起来很有希望,所以我做了一些调查,但找不到任何东西。如果重要的话,我可用的编译器是 clang++ 5.0 和 MSVC 19 (Visual Studio 2015)。

我的问题是,还有哪些其他工具/技术可以帮助将带有 lambda 函数的调用堆栈映射到相应的源代码行?

标签: c++debugginglambda

解决方案


恐怕这是不可能的。您应该设计自己的技术如何在 lamdas 中存储所需的信息。您的选项 2 适合这里。你可以看看它是如何谷歌:https ://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h

以下是非常原始的方法(https://ideone.com/OFCgAq

#include <iostream>
#include <stack>
#include <functional>

std::stack<std::function<void(void)>> someJobQueue;

template <typename T>
void submitJobToPool(std::string from_here, T callable) {
    someJobQueue.push(std::bind([callable](std::string from_here) { callable(); }, from_here));
}

void runJobFromPool() {
    auto job = someJobQueue.top();
    someJobQueue.pop();
    job();
}

int main() {
    submitJobToPool(__func__, [](){ std::cout << "It's me." << std::endl; });
    runJobFromPool();
    return 0;
}

不幸的是,您不会看到完美的调用堆栈。但是你可以from_here在调试器中看到。

void lambda_1a7009ccf8810b62b59083b4c1779e56() 0x345678920
void lambda_a7009ccf8810b62b59083b4c1779e569() 0x345678910  <-- Here `from_here` will be available: "main"
void runJobFromPool()                          0x234567890
int main(int, char**)                          0x123456780

推荐阅读