我正在研究用C ++编写的多线程进程,我正在考虑使用google-coredumper修改SIGSEGV处理,以便在发生分段错误时保持进程处于活动状态。
但是,使用google-coredumper似乎已经成熟,有机会陷入无限循环的核心转储,除非我以某种方式重新初始化线程和可能导致核心转储的对象。
在尝试通过核心转储使进程保持活动时,我应该记住哪些最佳做法?我应该注意哪些“陷阱”?
谢谢!
答案 0 :(得分:20)
在C中实际上是可能的。你可以用非常复杂的方式实现它:
1)覆盖信号处理程序
2)使用setjump()
和longjmp()
设置跳回的位置,并实际跳回到那里。
查看我写的这段代码(来自Peter Van Der Linden的“专家C编程:深度C秘密”的想法):
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
//Declaring global jmp_buf variable to be used by both main and signal handler
jmp_buf buf;
void magic_handler(int s)
{
switch(s)
{
case SIGSEGV:
printf("\nSegmentation fault signal caught! Attempting recovery..");
longjmp(buf, 1);
break;
}
printf("\nAfter switch. Won't be reached");
}
int main(void)
{
int *p = NULL;
signal(SIGSEGV, magic_handler);
if(!setjmp(buf))
{
//Trying to dereference a null pointer will cause a segmentation fault,
//which is handled by our magic_handler now.
*p=0xdead;
}
else
{
printf("\nSuccessfully recovered! Welcome back in main!!\n\n");
}
return 0;
}
答案 1 :(得分:8)
最佳做法是修复原始问题,导致核心转储并重新编译并重新启动应用程序。
要在野外部署之前捕获这些错误,请进行大量的同行评审并编写大量测试
答案 2 :(得分:4)
我对分段错误的经验是,很难以便携式捕获它们,并且在多线程上下文中进行移植几乎是不可能的。
这是有充分理由的:你真的期望在SIGSEGV之后内存(你的线程共享的内存)是完整的吗?毕竟,你刚刚证明某些寻址被破坏了,所以假设剩余的内存空间是干净的,这是非常乐观的。
考虑一个不同的并发模型,例如与流程。进程不共享其内存或仅共享其明确定义的部分(共享内存),并且一个进程可以合理地处理另一个进程何时死亡。当您拥有该程序的关键部分(例如核心温度控制)时,将其置于额外的进程中可以防止其他进程和分段错误导致内存损坏。
答案 3 :(得分:3)
如果发生分段错误,最好放弃进程。你怎么知道你的进程的任何内存在此之后都可用?如果程序中的某些东西弄乱了内存它不应该,为什么你认为它没有弄乱你的进程实际上可以访问而没有segfaulting的内存的其他部分呢?
我认为这样做最有利于攻击者。
答案 4 :(得分:3)
但遗漏的是,一旦你从信号处理程序恢复,它将无法再次工作,除非你取消屏蔽信号。以下是一大堆代码:
sigset_t signal_set;
...
setjmp(buf);
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGSEGV);
sigprocmask(SIG_UNBLOCK, &signal_set, NULL);
// Initialize all Variables...
请务必释放内存,插槽和其他资源,否则在发生这种情况时可能会泄漏内存。
答案 5 :(得分:0)
从coredumper的描述来看,它的目的不是你想要的,而只是允许制作过程记忆的快照。
就个人而言,我不会在触发核心转储之后继续保持流程 - 它可以通过很多方式来解决 - 并且会在重新启动流程后使用一些持久性来允许数据恢复。
而且,是的,正如parapura建议的那样,更好的是,找出导致SIGSEGV并修复它的原因。