2013-02-07 117 views
3

我已經看到至少有三種不同的方法來爲sigaltstack設置替代堆棧。我不知道哪一個是最好的辦法:如何正確設置sigaltstack?

方法#1

stack_t sigstk; 
sigstk.ss_size = 0; 
sigstk.ss_flags = 0; 
sigstk.ss_sp = mmap (NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 
if (sigstk.ss_sp != MAP_FAILED) { 
    sigstk.ss_size = SIGSTKSZ; 
    if (sigaltstack (&sigstk, 0) < 0) { 
     sigstk.ss_size = 0; 
     printf ("sigaltstack errno=%d\n", errno); 
    } 
} else { 
    printf ("malloc (SIGSTKSZ) failed!\n"); 
} 

方法2 (我們一直在使用這一段時間,但在這裏分配的內存泄漏檢測顯示出來(所述 '泄漏' 命令))

stack_t sigstk; 
sigstk.ss_size = 0; 
sigstk.ss_flags = 0; 
sigstk.ss_sp = malloc (SIGSTKSZ); 
if (sigstk.ss_sp != NULL) { 
    sigstk.ss_size = SIGSTKSZ; 
    if (sigaltstack (&sigstk, 0) < 0) { 
     sigstk.ss_size = 0; 
     free (sigstk.ss_sp); 
     printf ("sigaltstack errno=%d\n", errno); 
    } 
} else { 
    printf ("malloc (SIGSTKSZ) failed!\n"); 
} 

方法3

stack_t sigstk; 
static char ssp[SIGSTKSZ]; 
sigstk.ss_size = SIGSTKSZ; 
sigstk.ss_flags = 0; 
sigstk.ss_sp = ssp; 
sigstk.ss_size = SIGSTKSZ; 
if (sigaltstack (&sigstk, 0) < 0) { 
    sigstk.ss_size = 0; 
    free (sigstk.ss_sp); 
    printf ("sigaltstack errno=%d\n", errno); 
} 

由於,Ákos (Mac OS X 10.8.2)

回答

1

我對sigaltstack()不太熟悉,但我一直在評論the man page。 3種方法的區別似乎在於如何爲ss_sp結構成員分配空間:使用mmap(),使用傳統的malloc()或將其分配到堆棧之外。

如果我正確理解系統,那麼你絕對不需要想做的方法#3:從堆棧中分配。退出該功能後,堆棧空間將立即回收並重新調整用途(即更改),並會破壞sigaltstack()的功能。

所以我會推薦傳統的malloc()。如果你喜歡這個語法,你可以用mmap()。根據我的理解,將NULL地址傳遞給mmap()無論如何都相當於malloc()

+1

據我的理解,在方法#3中,'靜態'存儲類說明符將不允許變量超出範圍。 –

+0

啊,我沒注意到那個靜態限定符。感謝澄清。在這種情況下,所有的方法或多或少都有效,並且取決於您的個人偏好。或者你是否遇到了某種特定問題? –

+0

是的。我們現在使用第二種方法,但malloc'd內存出現在我們的泄漏檢測中。 –

2

方法#1是最好的。原因是因爲位置。假設你使用#2,你的代碼流是這樣的:

void *blah = malloc (...) 
... 
stack_t sigstk; 
sigstk.ss_size = 0; 
sigstk.ss_flags = 0; 
sigstk.ss_sp = malloc (SIGSTKSZ); 

現在,如果你在你的信號處理用盡你的棧空間會發生什麼?您的堆棧將向下增長並干擾blah指向的內存。如果你在某處有一些淺層遞歸,很容易發生。 #3有同樣的問題。

相反,使用mmap因爲它從不同的池分配,遠離數據堆,這是一個好主意,設置防護頁面:

char* mem = mmap (NULL, 
        SIGSTKSZ + 2*getpagesize(), 
        PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 
        -1, 0); 
mprotect(mem, getpagesize(), PROT_NONE); 
mprotect(mem + getpagesize() + SIGSTKSZ, getpagesize(), PROT_NONE); 
sigstk.ss_sp = mem + getpagesize(); 
... 

現在你會得到一個SIGSEGV如果發生堆棧溢出,比隨機存儲器覆蓋更容易調試10億次。 :)

原因#2被視爲泄漏可能是誤報。您正在使用的泄漏工具可能會使用其自己的變體覆蓋malloc庫函數,這是爲此任務傾向於使用mmap而不是malloc的另一個原因。