2014-10-17 28 views
0

以下是我在Wikipedia上看到的代碼。這是否會導致堆棧溢出?setovertext中的Stackoverflow()

#include <stdio.h> 
#include <ucontext.h> 
#include <unistd.h> 

int main(int argc, const char *argv[]){ 
    ucontext_t context; 

    getcontext(&context); 
    puts("Hello world"); 
    sleep(1); 
    setcontext(&context); 
    return 0; 
} 

原因:當代碼達到setcontext()時,它會在堆棧上推送新幀。由於setcontext()不返回,它的推送幀將保持在堆棧上。隨着程序處於無限循環,它會繼續在堆棧上推送新的幀,導致堆棧溢出。

+2

當你嘗試時發生了什麼? – 2014-10-17 07:59:42

+0

你可以在http://pubs.opengroup.org/onlinepubs/007908775/xsh/getcontext.html閱讀getcontext/setcontext描述。它提到setcontext只能恢復上下文,並沒有提到推送新堆棧幀的任何信息。 – SSC 2014-10-17 08:21:42

+0

@MartinJames這是一個無限循環。它將繼續打印「Hello World」 – Ravi 2014-10-17 09:23:37

回答

1

setcontext將使堆棧恢復到它在getcontext處的狀態。

當您撥打setcontext時,會將新的堆棧幀壓入堆棧。然後setcontext會將堆棧恢復到它看上去的方式getcontext,從而有效地移除框架。

所以程序確實創建了一個無限循環,但它不會導致堆棧溢出。

2

GDB否則說:

(gdb) list 
1 #include <stdio.h> 
2 #include <ucontext.h> 
3 #include <unistd.h> 
4 
5 int main(int argc, const char *argv[]){ 
6  ucontext_t context; 
7 
8  getcontext(&context); 
9  puts("Hello world"); 
10  //sleep(1); 
(gdb) break 9 
Breakpoint 1 at 0x4005bb: file test.c, line 9. 
(gdb) run 
Starting program: /home/dtarcatu/workspace/ctest/test 

Breakpoint 1, main (argc=1, argv=0x7fffffffe008) at test.c:9 
9  puts("Hello world"); 
(gdb) print $rbp 
$1 = (void *) 0x7fffffffdf20 
(gdb) print $rsp 
$2 = (void *) 0x7fffffffdb60 
(gdb) c 
Continuing. 
Hello world 

Breakpoint 1, main (argc=1, argv=0x7fffffffe008) at test.c:9 
9  puts("Hello world"); 
(gdb) print $rbp 
$3 = (void *) 0x7fffffffdf20 
(gdb) print $rsp 
$4 = (void *) 0x7fffffffdb60 
(gdb) c 
Continuing. 
Hello world 

Breakpoint 1, main (argc=1, argv=0x7fffffffe008) at test.c:9 
9  puts("Hello world"); 
(gdb) print $rbp 
$5 = (void *) 0x7fffffffdf20 
(gdb) print $rsp 
$6 = (void *) 0x7fffffffdb60 

我不熟悉這些內容處理功能,但它似乎setcontext不推新幀到堆棧而是恢復堆棧正是它的方式。所以你最終只會陷入一個無限循環 - 沒有堆棧溢出...

+1

謝謝@dragosht。當任何函數被調用時,棧幀被推送。如果你嘗試像'(gdb)break setcontext(gdb)info registers ebp esp',你會從其他斷點獲得不同的esp。內部setcontext通過設置先前保存在getcontext()中的esp來覆蓋它自己的堆棧框架,這就是爲什麼每次都得到相同的esp。所以存在無限循環但沒有堆棧溢出。 – Ravi 2014-10-17 09:59:54