给定一个包含lambda函数的调用堆栈,如何确定其来源?

时间:2018-05-17 15:25:05

标签: c++ debugging 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提供更有意义的名称/添加调试信息。
  5. 第四个选项看起来很有希望,所以我做了一些调查,但找不到任何东西。如果它很重要,我可用的编译器是clang ++ 5.0和MSVC 19(Visual Studio 2015)。

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

1 个答案:

答案 0 :(得分:2)

我担心这是不可能的。您应该设计自己的技术,如何在lamdas中存储所需的信息。您的选项2适用于此处。您可以查看Google如何: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