分叉过程的零星堆栈指针分割故障

时间:2012-12-01 16:44:50

标签: c++ linux process embedded-linux

我正在尝试调试一个进程,该进程偶尔会在访问堆栈指针时出现分段错误。

用于在main()的第一行之前进行段错误的过程{ 现在,segfault转移到了另一个地方。

如果它没有崩溃,那么该过程将继续无限期地正确运行。

我猜这与进程实例化的方式有关:

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 <memset@plt>

(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”也会在数百次来自shell时崩溃:

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

我应该提交新问题还是修改这个问题?

1 个答案:

答案 0 :(得分: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,当我尝试执行它时,我得到了这个:

ottavio@magritte:/tmp$ ulimit -s
8192
ottavio@magritte:/tmp$ ./x 
Segmentation fault

但如果我增加堆栈大小就行了

ottavio@magritte:/tmp$ ulimit -s 16384
ottavio@magritte:/tmp$ ./x 
Hello There!
ottavio@magritte:/tmp$