在 SIGSEGV 信号后打破无限循环

Break Infinite Loop After SIGSEVG Signal

我试图通过我的程序找到我的最大堆栈大小。我知道,在我的 OS 上,堆栈的最大大小约为 8MB。所以我试图进行无限循环,直到它导致分段错误。然后我需要打破这个循环,这样我才能计算大小。我怎样才能做到这一点?在 SIGSEGV 信号之后有什么办法可以打破无限循环吗?

 static void handler(int signo)
    {
        if(signo == SIGSEGV)
        {
            printf("Waoh, caught signal\n");
        }
    }

    int main()
    {
        int counter = 8964;
        stack_t sigstack;
        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;

        if(sigaltstack(&sigstack, NULL) == -1)
        {
            printf("Err: sigaltstack error\n");
            exit(EXIT_FAILURE);
        }
        struct sigaction act;
        act.sa_flags = SA_ONSTACK;
        sigemptyset(&act.sa_mask);
        act.sa_handler = handler;
        sigaction(SIGSEGV, &act, NULL);

        do
        {
            char a[counter];
            counter += 8964;
        } while (1);

        return 0;
    }

我修改了你的程序来计算堆栈大小的估计值,然后使用 siglongjmp 到 return 从信号处理程序到 main 就在分配可变长度数组的循环之前。 (请注意,可变长度数组的分配方式取决于编译器,并且可能没有安全的方法在 main 溢出堆栈后恢复执行)。

信号处理程序中的printf只是为了调试;可以删除它们而不影响程序的其余部分。

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

ptrdiff_t s_size_computed;
void *s_base_estimated;
sigjmp_buf env;

void handler (int signo, siginfo_t *info, void *ucontext)
{
        printf("Caught signal %d\n", signo);
        if (signo == SIGSEGV)
        {
                printf("faulting address %p\n", info->si_addr);
                s_size_computed = (char *)s_base_estimated - (char *)info->si_addr;
                siglongjmp(env, 1);
        }
}

int main()
{
        int counter = 8964;
        stack_t sigstack;
        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;

        if (sigaltstack(&sigstack, NULL) == -1)
        {
                printf("Err: sigaltstack error\n");
                exit(EXIT_FAILURE);
        }
        s_base_estimated = &counter;
        printf("&locals %p\n", s_base_estimated);
        struct sigaction act;
        act.sa_flags = SA_ONSTACK|SA_SIGINFO;
        sigemptyset(&act.sa_mask);
        act.sa_sigaction = handler;
        sigaction(SIGSEGV, &act, NULL);
        if (sigsetjmp(env, 0) == 1)
        {
                printf("computed stack size %td\n", s_size_computed);
                exit(1);
        }
        do
        {
                char a[counter];
                counter += 8964;
                a[0] = 0;         /* access element closest to top of stack (x86) */
        } while (1);

        return 0;
}

这是我的 Ubuntu 系统的输出:

mp:~$ ./stack
&locals 0x7fffeb60e0dc
Caught signal 11
faulting address 0x7fffeae0d960
computed stack size 8390524
mp:~$ ulimit -s
8192