약간의 보살핌. 할당 한 스택을 사용하도록 프로그램을 설정하면 주어진 스택의 끝을지나 첫 페이지에 대한 읽기 및 쓰기를 "가드 페이지"에 추가 할 수 있습니다. 그런 다음 신호 처리기를 설치하여 신호를 잡아 당김 오류가 해당 가드 페이지 내에서 액세스로 인해 발생했는지 여부를 알려줄 수 있습니다.
#include <stdio.h>
#include <ucontext.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <malloc.h>
#include <signal.h>
static char *guard = NULL;
static const int pagesize = getpagesize();
static void handler(int sig, siginfo_t *info, void *ctx) {
if ((char*)info->si_addr >= guard && (char*)info->si_addr - guard <= pagesize) {
write(2, "stack overflow\n", 15);
}
write(2, "sigsegv caught\n", 15);
_exit(-1);
}
static void install_handler() {
// register sigsegv handler:
static struct sigaction act;
act.sa_sigaction = handler;
sigemptyset(&act.sa_mask);
act.sa_flags=SA_SIGINFO|SA_ONSTACK;
// give the signal handler an alternative stack
static char stack[4096];
stack_t ss;
ss.ss_size = sizeof(stack);
ss.ss_sp = stack;
if (sigaltstack(&ss, 0)) {
perror("sigaltstack");
fprintf(stderr,"failed to set sigstack\n");
exit(-1);
}
if (sigaction(SIGSEGV, &act, NULL)) {
perror("sigaction");
fprintf(stderr,"failed to set handler\n");
exit(-1);
}
}
static int overflow() {
return overflow() + 1;
}
static void test()
{
install_handler();
puts("start test");
// real code that might overflow
// test non-overflow segv
//*(char*)0 = 0;
// test overflow
overflow();
puts("finish test");
}
int main()
{
// create a stack and guard page:
const int pagesize = getpagesize();
char *st1=(char*)memalign(pagesize,1+(pagesize*4));
guard = st1+(pagesize*4);
if (mprotect(guard, pagesize, PROT_NONE)) {
perror("mprotect");
fprintf(stderr,"failed to protect guard page: %p \n", guard);
return -1;
}
ucontext_t ctx[2];
getcontext(&ctx[1]);
ctx[1].uc_stack.ss_sp = st1;
ctx[1].uc_stack.ss_size = 4*pagesize;
ctx[1].uc_link = &ctx[0];
makecontext(&ctx[1], test, 0);
swapcontext(&ctx[0], &ctx[1]);
return 0;
}
을뿐만 아니라 당신이 신호가 될 또 다른 스택을 제공 할 필요가에서 코드를 실행하는 데 자신의 스택을 사용 :
이 내가 그렇게 만들 수있는 가장 작은 예입니다이 작업을 수행하는 방법을 보여줍니다 를 사용하여 전달하면 그렇지 않으면 가드 페이지로 인해 신호 전달 자체가 실패합니다.
코드의 해당 부분을 디버깅하여 과도한 스택 사용을 찾으셨습니까? 스택 크기를 늘리면 완벽하게 좋은 해결책이 될 수 있지만 문제를 일으키는 미묘한 버그가있을 수 있습니다. – sean
왜 GCC v4.0.0에 제약이 있습니까? 최신 버전은 이전 버전에 의해 빌드 된 객체 및 라이브러리와 하위 호환이 가능하지만, 어떤 이유로 든 이전 버전을 사용해야하는 경우에도 새로운 버전을 설치하고이 문제를 찾기 위해 사용할 수 있습니다. 과거의 컴파일러로 과거에 살았습니다. GCC 코드의 주요 재 작성에 이어 4.0.0이 처음 출시되었습니다. 적어도 4.0.4는 사용할 수 있습니다. –
@JonathanWakely : 가능하면 컴파일러는 임베디드 칩을 제공 한 공급 업체가 제공합니다. – jxh