2012-12-01 34 views
3

我正試圖調試一次在分段出現故障時訪問堆棧指針的過程。分叉進程的零星堆棧指針分段錯誤

在main()的第一行之前用於segfault的過程{ 現在seg段移動到了另一個地方。

如果它沒有崩潰,那麼該進程將繼續無限期地正確運行。

我猜測,這是關係到過程實例的方式:

pid_t COsAbstraction::Start(const uint32_t coreId, const char* argv[]) 
{ 
    pid_t pid; 
    sigset_t mask; 
    sigset_t save; 

    /* 
    * Block SIGCHLD 
    */ 
    sigemptyset(&mask); 
    sigaddset(&mask, SIGCHLD); 
    pthread_sigmask(SIG_BLOCK, &mask, &save); 

    pid = fork(); 
    if(pid < 0) 
    { 
     _exit(false); 
    } 
    if (pid != 0) 
    { 
     // I am the parent 
     pthread_sigmask(SIG_UNBLOCK, &save, NULL); 
     return pid;; 
    } 
    // I am the child 
    // Replace myself with the desired process 
    execvp(argv[ 0 ], const_cast<char**>(argv)) 

    _exit(0); 

}

崩潰代碼(零星):

(gdb) disassemble 
Dump of assembler code for function main: 
0x0804c663 <main+0>: lea 0x4(%esp),%ecx 
0x0804c667 <main+4>: and $0xfffffff0,%esp 
0x0804c66a <main+7>: pushl -0x4(%ecx) 
0x0804c66d <main+10>: push %ebp 
0x0804c66e <main+11>: mov %esp,%ebp 
0x0804c670 <main+13>: push %edi 
0x0804c671 <main+14>: push %esi 
0x0804c672 <main+15>: push %ebx 
0x0804c673 <main+16>: push %ecx 
0x0804c674 <main+17>: sub $0x525a8,%esp 
0x0804c67a <main+23>: call 0x804a22e <__i686.get_pc_thunk.bx> 
0x0804c67f <main+28>: add $0x6125,%ebx 
0x0804c685 <main+34>: mov (%ecx),%eax 
0x0804c687 <main+36>: mov %eax,-0x52578(%ebp) 
0x0804c68d <main+42>: mov 0x4(%ecx),%ecx 
0x0804c690 <main+45>: mov %ecx,-0x5257c(%ebp) 
0x0804c696 <main+51>: movl $0x0,-0x418(%ebp) 
0x0804c6a0 <main+61>: movl $0x400,0x8(%esp) 
0x0804c6a8 <main+69>: movl $0x0,0x4(%esp) 
0x0804c6b0 <main+77>: lea -0x410(%ebp),%eax 
0x0804c6b6 <main+83>: mov %eax,(%esp) 
0x0804c6b9 <main+86>: call 0x8049c4c <[email protected]> 

(gdb) info registers 
eax   0xf746d564  -146352796 
ecx   0xf746d4e0  -146352928 
edx   0xf746d500  -146352896 
ebx   0x444a7ff4  1145733108 
esp   0xf741af10  0xf741af10 
ebp   0xf746d4c8  0xf746d4c8 
esi   0x8050b30  134548272 
edi   0x8049d90  134520208 
eip   0x804c67a  0x804c67a <main+23> 
eflags   0x210282 [ SF IF RF ID ] 
cs    0x23  35 
ss    0x2b  43 
ds    0x2b  43 
es    0x2b  43 
fs    0x0  0 

此代碼對24運行核心的RedHat Linux 2.6設備。

更新:

原來的崩潰與調用過程無關! 簡單的「Hello World」也崩潰時上百次從殼:

#include <stdio.h> 
int main(int argc, char* argv[]) 
{ 
    char a[100*1024]; 
    a[0] = '1'; 
    printf("Hello There!\n"); 
    return 0; 
} 

我應該提出一個新的問題或修改這一個?

+0

那麼的代碼行它在? –

+0

它在get_pc_thunk上的main()的{}上崩潰。 eip = 0x804c67a 。較新的崩潰發生在movl $ 0x04,0x4(%esp)上。嘗試訪問該地址處的堆棧會導致段錯誤。偶爾一個進程被實例化,堆棧太短。 – yaronkle

+0

這對我來說就像壞RAM一樣。 – zwol

回答

0

C程序崩潰,因爲您正在退出程序堆棧。

的一點是,像

char a[100*1024]; 

一個變量是在棧上分配的,它的大小是有限的,當你指向你從堆棧如果進程退出陣列的開始。

給你舉一個例子,我只是修改了代碼,因爲我在AMD64,所以我有

#include <stdio.h> 
int main(int argc, char* argv[]) 
{ 
    char a[12*1024*1024]; 
    a[0] = '1'; 
    printf("Hello There!\n"); 
    return 0; 
} 

,所以我試圖把一個12 MB變量在堆棧中。堆棧,你可以看到的默認大小爲8MB,當我試圖執行它,我得到這個:

[email protected]:/tmp$ ulimit -s 
8192 
[email protected]:/tmp$ ./x 
Segmentation fault 

但如果我增加堆棧大小它的工作原理

[email protected]:/tmp$ ulimit -s 16384 
[email protected]:/tmp$ ./x 
Hello There! 
[email protected]:/tmp$ 
+0

默認堆棧大小8Meg遠高於示例代碼中分配的100K。 500次運行中發生了一次或兩次撞車事故。如果堆棧太小,它應該每次都崩潰。 – yaronkle