假设我们有以下代码:
#include <exception>
void funcA() {
funcB();
}
void funcB() {
funcC();
}
void funcC() {
funcD();
}
void funcD() {
throw std::runtime_error("Exception!!"); //3
}
void funcE() {
int * p;
delete p; //4
}
int main (int argc, char **argv) {
try {
funcA(); //1
} catch (std::exception exc) {
std::cerr << exc.what() << endl; //2
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
我想以多线程高效的方式打印堆栈跟踪以及抛出的异常的行号。
过去几天我一直在检查人们正在做的解决方案和方法,但不幸的是对我来说没有任何用处。例如,我可以使用
boost::stacktrace::stacktrace()
中的 boost 库 //2
或任何其他库,但这里的问题是我必须捕获异常才能执行此操作,如果您的代码有数百个嵌套函数,则这种方法效率不高。您不能只是检查所有这些并用 try-catch
包裹每一个并单独处理它们。
所以基本上我需要做的是,如果在
//3
抛出异常,我应该能够在 `//2 中打印异常的堆栈跟踪
我知道堆栈展开及其工作原理,但据我所知,每当您的代码到达 catch 块时,这意味着异常堆栈已展开并且您无法获取它。 如有错误请指正!
有没有办法至少在展开异常堆栈之前添加类似于中间件的东西?还是我必须手动完成?
另外,当我可以
funcE()
时会发生什么是内存访问异常,但这个异常永远不会被捕获。有没有办法捕获此类异常或至少在崩溃之前打印其堆栈跟踪?
我正在 Linux 和 macOS、C++11 上使用 Silicon Web 框架运行我的代码。 这是一个很大的系统,所以我正在尝试实现一些可以跨系统使用的日志记录机制。
我发布此内容是为了防止有人遇到同样的问题并想要快速有用的答案。
我最终使用这个 gist
覆盖了主要的 C++ 抛出异常行为我更改了
__cxa_throw
函数中的一些内容来解决我自己的问题,并使用 boost::stacktrace
获得更易于理解的堆栈跟踪。
#include <dlfcn.h>
#include <execinfo.h>
typedef void (*cxa_throw_type)(void *, void *, void (*) (void *));
cxa_throw_type orig_cxa_throw = 0;
void load_orig_throw_code()
{
orig_cxa_throw = (cxa_throw_type) dlsym(RTLD_NEXT, "__cxa_throw");
}
extern "C"
void __cxa_throw (void *thrown_exception, void *pvtinfo, void (*dest)(void *)) {
printf(" ################ DETECT A THROWN !!!!! #############\n");
if (orig_cxa_throw == 0)
load_orig_throw_code();
{
static int throw_count = 0;
void *array[10];
size_t size;
size = backtrace(array, 10);
fprintf(stderr, "#### EXCEPTION THROWN (#%d) ####\n", ++throw_count);
backtrace_symbols_fd(array, size, 2); // 2 == stderr
}
orig_cxa_throw(thrown_exception, pvtinfo, dest);
}