【问题标题】:How to use "sigaltstack" in signal handler program?如何在信号处理程序中使用“sigaltstack”?
【发布时间】:2011-04-26 03:57:31
【问题描述】:

有人知道如何在真正的信号处理程序中使用sigaltstack 吗?一个简单但完整的代码可能会有很大帮助!

【问题讨论】:

  • // ,这可能会使用一些格式改进。到目前为止,您尝试过什么吗?它对你有用吗?

标签: c posix signals


【解决方案1】:

这是一个使用sigaltstack 捕获无限递归的最小示例程序。如果注释掉sigaltstack 调用或SA_ONSTACK 标志,则信号处理程序将无法运行,因为它没有剩余堆栈,程序将崩溃。

#define _XOPEN_SOURCE 700
#include <signal.h>
#include <unistd.h>
void handler(int sig)
{
    write(2, "stack overflow\n", 15);
    _exit(1);
}
unsigned infinite_recursion(unsigned x) {
    return infinite_recursion(x)+1;
}
int main()
{
    static char stack[SIGSTKSZ];
    stack_t ss = {
        .ss_size = SIGSTKSZ,
        .ss_sp = stack,
    };
    struct sigaction sa = {
        .sa_handler = handler,
        .sa_flags = SA_ONSTACK
    };
    sigaltstack(&ss, 0);
    sigfillset(&sa.sa_mask);
    sigaction(SIGSEGV, &sa, 0);
    infinite_recursion(0);
}

更复杂的用法可能实际上执行siglongjmp 以跳出信号处理程序并返回到可以避免无限递归的点。如果正在使用 async-signal-unsafe 库调用,或者您的数据可能处于不安全/不可恢复的状态,则此方法无效,但如果您正在执行纯算术计算,则它可能是有效的。

对于信号处理程序来说,更好的任务可能是对尚未保存到磁盘的任何有价值/关键数据执行紧急转储。如果您不能调用 async-signal-unsafe 函数,这可能会很困难,但如果您付出一些努力,这通常是可能的。

【讨论】:

  • 它对我来说很好用(在修正了一个错字之后)。顺便说一句,启用优化后,gcc 会为函数生成无限循环而不是递归,因此永远不会溢出堆栈。使用-O0,信号处理程序按预期运行。
  • 我按照你的说法尝试了 -O0 ,但它仍然给我一个分割错误。可以是gcc版本吗?
  • 在某些系统上,堆栈溢出可能会给出SIGSTKFLT 而不是SIGSEGV,因此您可能需要同时处理这两者才能“便携”。
  • @Hola Soy Edu,您是否将ss指定的初始化列表 设置为@R..?如果没有,问题可能出在ss.ss_flags。对于establish a new alternate signal stack,它必须是。我会建议进行修改以强调这一点。
  • @Mawg:看起来像。不过,那是很久以前的事了,
【解决方案2】:
#define _GNU_SOURCE
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

static void handler(int signo)
{
    int x;
    if(signo == SIGSEGV)
    {
        printf("Waoh, caught signal %s\n",strsignal(signo));
        printf("Top of stack is near %10p", (void*)&x);
    }
    _exit(EXIT_FAILURE);
}

static void overflowStack(int i)
{
    char a[8964];
    printf("(%d) Called overflow function. The top of stack is near %10p\n",i ,&a[0]);
    overflowStack(i+1);
}

int main(int argc, char *argv[])
{


    /*(1)specify that the signal handler will be allocated onto the
    alternate signal stack*/
    stack_t sigstack;
    //malloc return the pointer to the allocated memory on success
    //malloc return NULL on error
    sigstack.ss_sp = malloc(SIGSTKSZ);
    if( sigstack.ss_sp == NULL)
    {
        printf("Err: malloc error\n");
        exit(EXIT_FAILURE);
    }
    sigstack.ss_size = SIGSTKSZ;
    sigstack.ss_flags = 0;

    /*(2)Specify that the signal handler will be allocated on the alternate 
    signal stack */
    if(sigaltstack(&sigstack, NULL) == -1)
    {
        printf("Err: sigaltstack error\n");
        exit(EXIT_FAILURE);
    }
    // sbrk() change the location of the program break, which defines the end of the process's data segment 
    //On success, sbrk() returns the previous program break. 
    printf("Now the alternate signal stack is successfully allocated\n");
    printf("The address of signal stack is : %10p - %10p\n",sigstack.ss_sp,(char*)sbrk(0)-1);

    /*(3)define a struct sigaction to deal with the SIGSEGV*/
    struct sigaction act;
    act.sa_flags = SA_ONSTACK;
    sigemptyset(&act.sa_mask);
    act.sa_handler = handler;
    sigaction(SIGSEGV, &act, NULL);

    overflowStack(1);

}

【讨论】:

  • 输出:现在备用信号栈分配成功信号栈地址为:0x563078b3c260 - 0x563078b5cfff (1)调用溢出函数。栈顶在 0x7ffdad9eed00 附近 (2) 调用溢出函数。栈顶在 0x7ffdad9ec9d0 附近 (3) 调用溢出函数。栈顶接近 0x7ffdad9ea6a0 (929) 称为溢出函数。栈顶在0x7ffdad1f5f00附近哇哦,抓到信号Segmentation fault
猜你喜欢
  • 2016-03-31
  • 2020-03-31
  • 2014-06-12
  • 1970-01-01
  • 1970-01-01
  • 2017-11-05
  • 2018-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多