C语言 捕获SIGSEGV异常

56lgkhnf  于 2023-02-11  发布在  其他
关注(0)|答案(2)|浏览(227)

我尝试使用一个异常处理器来捕捉错误的内存访问,但我不完全确定如何去做。我尝试用sigaction注册它,但我的处理器没有触发。
旧代码

#include <stdio.h>
#include <signal.h>
void handler(int sig)
{
    //exception should land here
    printf("caught exception");
    
}
int main(int argc, const char * argv[]) {

    struct sigaction act;
    
    act.sa_flags = SA_SIGINFO;
    sigemptyset(&act.sa_mask);
    act.sa_handler = handler;
    if(sigaction(SIGSEGV, &act, NULL)==-1){
        printf("Could not register handler");
    }else{
        printf("handler registered\n");
    }
    *(int*)0 = 0;//throw exception
    
    return 0;
}

一旦进入处理程序,我如何读取线程上下文寄存器?我也在MacOS上,所以我不确定是否有任何操作系统特定的实现。
编辑:新代码

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#define _XOPEN_SOURCE 600
#include <ucontext.h>
void handler(int sig, siginfo_t *info, void *uc)
{
    (void) sig;
    write (STDOUT_FILENO, "Caught exception\n", 17);
    struct ucontext* mc = (struct ucontext*)uc;
}
int main(int argc, const char * argv[]) {

    struct sigaction act;
    
    act.sa_flags = SA_SIGINFO;
    sigemptyset(&act.sa_mask);
    act.sa_handler = handler;
    if(sigaction(SIGSEGV, &act, NULL)==-1){
        printf("Could not register handler");
    }else{
        printf("handler registered\n");
    }
    raise (SIGSEGV);
    return 0;
}

当我包含ucontext.h时,我的编译器遇到了这个错误

#else /* !_XOPEN_SOURCE */
#error The deprecated ucontext routines require _XOPEN_SOURCE to be defined
#endif /* _XOPEN_SOURCE */

我通过定义_XOPEN_SOURCE解决了这个问题,但是编译器仍然不知道ucontext是什么,因为我没有得到任何智能..我可能必须自己定义这个结构
编辑:因为我是在M1上,所以我是从ARM而不是x86_64编译的,ucontext和mcontext都必须使用64位变体。

3duebb1j

3duebb1j1#

    • 未定义的行为不可靠:**

不要依赖它,而是使用raise()向调用进程发送一个信号:

raise (SIGSEGV);

因此代码变为:

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

#include <unistd.h>

static void func (int signo, siginfo_t *info, void *context);
{  
    write (STDOUT_FILENO, "Caught exception\n", 17);
    
    /* Restores the default handler. This is the only
     * portable use of signal().
     */
    signal (sig, SIG_DFL);
    raise (sig); 
}

int main (int argc, char *argv[])
{
    struct sigaction act;

    act.sa_flags = SA_SIGINFO;

    /* Upon successful  completion, sigemptyset() shall return 0;
     * otherwise, it shall return -1 and set errno to indicate the error.
     */
    if (sigemptyset (&act.sa_mask) == -1) {
        perror ("sigemptyset()");
        return EXIT_FAILURE;
    }
    act.sa_sigaction = handler;

    if (sigaction (SIGSEGV, &act, NULL) == -1) {
        fprintf (stderr, "Could not register handler\n");
    } else {
        fprintf (stderr, "handler registered\n");
    }

    raise (SIGSEGV);
    return EXIT_SUCCESS;
}
    • 输出:**
handler registered
caught exception
    • 将错误消息打印到stderr:**
//printf ("Could not register handler\n"); 

fprintf (stderr, "Could not register handler.\n");
    • 不要在信号处理程序中调用异步信号不安全函数:**

无论是C标准还是POSIX标准都没有指定printf()是异步信号安全的,这意味着它不能在信号处理程序内部被安全地调用。
不过,POSIX标准确实指定write()是异步信号安全的,所以printf()应该用它来代替。

// printf ("Caught exception\n");

write (STDOUT_FILENO, "Caught exception\n", 17);
    • handler()的声明不正确:**

如果设置了SA_SIGINFO,则void handler(int sig)不正确:"如果设置了SA_SIGINFO,并且捕获了信号,则信号捕获函数应输入为:void func(int signo, siginfo_t *info, void *context); "-@安德鲁·亨勒

//void func (int signo);

void func(int signo, siginfo_t *info, void *context);
    • handler()分配给正确的成员:**

sigaction结构定义如下:

struct sigaction {
     void (*sa_handler)(int);
     void (*sa_sigaction)(int, siginfo_t *, void *);
     sigset_t sa_mask;
     int sa_flags;
     void (*sa_restorer)(void);
};

使用SA_SIGINFO标志时,需要将信号处理函数分配给.sa_sigaction,而不是.sa_handler

// act.sa_handler = handler;

sig.sa_sigaction = handler;
ru9i0ody

ru9i0ody2#

您的第一个问题似乎已经得到了解答,所以我不再深入讨论。至于您的第二个问题,Apple对mcontext和ucontext有自己的定义,特别是mcontext 64和ucontex 64。此外,您正在针对ARM 64而不是x86_64进行编译,因此这些寄存器将不再存在于您编译的二进制文件中。
进入你的构建设置-〉架构移除标准架构并用x86_64替换它,你的处理程序应该能够访问寄存器。

相关问题