0

您好我正在尝试测试代码以查看它是否旨在处理内存问题。
不幸的是,我必须通过 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? */
}
4

3 回答 3

1

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

我相信您正在寻找的是代替您的 exit(0) 语句的异常,但 Segmentation Fault 不是异常,因此难以处理。话虽如此,C 似乎没有内置异常处理。

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

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

于 2013-07-11T05:49:31.557 回答
1

可以使用信号处理程序加setjmp/来完成longjmp

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

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

下面的代码主要基于这个答案

#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;
}
于 2013-07-11T19:13:50.787 回答
0

如果您确切知道函数中的什么会导致 SEGV,您可以尝试在信号处理程序中设置一个标志。(实际上,请注意,您可以从信号处理程序中调用的函数集非常有限,因此设置标志实际上是您可以做的所有事情。)

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

另外,请注意,根据 POSIX.1, SIGFPE, SIGILL, 和SIGSEGV被显式调用,这样当信号处理程序完成时,行为是未定义的。对于任何其他信号,“程序应在中断点恢复执行”。

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

于 2013-07-11T18:18:34.393 回答