我如何退出导致segfault并返回调用函数的函数

时间:2013-07-11 05:39:44

标签: c cunit

您好我正在尝试测试代码以查看它是否旨在处理内存问题 不幸的是,我必须通过c-unit来做到这一点,它不能很好地处理分段错误(只是崩溃) 所以我的问题是我可以为我正在测试的代码添加一个信号处理程序,以允许它退出违规函数而不是退出整个程序吗?

基本上我可以修改以下处理程序以退出函数并返回到我的cunit框架吗?

void sighandler(int signo, siginfo_t *si, ucontext_t* context)
{
  printf("Handler executed for signal %d\n", signo);
  exit(0); /* can i replace this with exit from function? */
}

3 个答案:

答案 0 :(得分:1)

这是一个类似的问题和答案(尽管语言错误,C ++): Catch Segfault or any other errors/exceptions/signals in C++ like catching exceptions in Java

我相信你所寻找的是一个例外代替你的exit(0)语句,但是Segmentation Fault也不例外,因此很难处理。这就是说,似乎C没有内置的异常处理。

无论如何,这里有关于c ++中接收的参考:http://www.cplusplus.com/doc/tutorial/exceptions/

我不确切知道你是如何使用这里的函数的,但也许你可以返回一个布尔值而不是void,如果布尔值为真,则从调用函数返回?

答案 1 :(得分:1)

可以使用信号处理程序加上setjmp / longjmp

我不确定这个解决方案有多可靠。它在我测试它时有效,但可能包含未定义的行为,所以不要依赖它。

同样重要的是要注意有缺陷的代码可能比分段错误做得更糟。例如,它可能会破坏内存,因此您的测试代码或其他经过测试的代码将会失败。

以下代码主要基于this answer

#include <stdio.h>
#include <signal.h>
#include <setjmp.h>

static void good_func(void)
{
    int q, *p = &q;
    printf("%s running\n", __FUNCTION__);
    *p = 3;

}
static void bad_func(void)
{
    int *p = NULL;
    printf("%s running\n", __FUNCTION__);
    *p = 3;
}

static jmp_buf  context;

static void sig_handler(int signo)
{
    longjmp(context, 1);
} 

static void catch_segv(int catch)
{
    struct sigaction sa;

    if (catch) {
        memset(&sa, 0, sizeof(struct sigaction));
        sa.sa_handler = sig_handler;
        sa.sa_flags = SA_RESTART;
        sigaction(SIGSEGV, &sa, NULL);
    } else {
        sigemptyset(&sa);
        sigaddset(&sa, SIGSEGV);
        sigprocmask(SIG_UNBLOCK, &sa, NULL);
    }
}

typedef void (*func_t)(void);

static int safe_run(func_t func)
{
    catch_segv(1);

    if (setjmp(context)) {
            catch_segv(0);
            return 0;
    }

    func();
    catch_segv(0);
    return 1;
}

int main()
{
    printf("good_func is %s\n", safe_run(good_func) ? "good" : "bad");
    printf("bad_func is %s\n",  safe_run(bad_func) ?  "good" : "bad");
    return 0;
}

答案 2 :(得分:0)

如果您确切知道函数中预期会导致SEGV的内容,您可以尝试在信号处理程序中设置一个标志。 (实际上,请注意,您允许在信号处理程序中调用的函数集非常有限,因此设置标志几乎是您无论如何都可以做的。)

将您的标志变量声明为volatile int caused_segv = 0,让您的信号处理程序设置为caused_segv = 1,并在您的代码中,在执行可能引发SIGSEGV的操作后,检查caused_segv是否为非零。< / p>

另请注意,根据POSIX.1,SIGFPESIGILLSIGSEGV被明确调出,以便在信号处理程序完成时,行为未定义。对于任何其他信号,“程序应在被中断时恢复执行。”

所以,你的问题的答案实际上是,你不能可靠地做你想做的事,因为让SIGSEGV自动让你处于未定义的行为状态,但你可以使用我给的你上面试试。