【问题标题】:what is causing SIGSEV?是什么导致了 SIGSEGV?
【发布时间】:2014-04-26 00:53:49
【问题描述】:

/*

从所有帖子中学习 - 如果我错了,请纠正我..

现在这很有意义-如果我没记错的话,堆栈是固定内存段-在程序启动时分配...而虚拟内存可以使用 malloc、realloc、free 以编程方式调整大小/大小... 结构指针数组 -

长尺寸 = 10000000; struct foo *bar[size];

应该从堆中分配 - 使用 malloc()... 而不仅仅是一个固定大小的堆栈(程序文本)

*/

这个 SIGSEV 的:

#include <stdio.h>
#include <stdlib.h>

int main(void) {

    struct foo {
        int x;
        char s[5];
    };

    long size = 10000000;
    struct foo *bar[size];

    long i = 0;
    while (i < size) {
        printf("%ld \n", i);
        i++;
    }
}

这个有效 - 注释掉 struct foo 指针数组:

#include <stdio.h>
#include <stdlib.h>

int main(void) {

    struct foo {
        int x;
        char s[5];
    };

    long size = 10000000;
    //struct foo *bar[size];

    long i = 0;
    while (i < size) {
        printf("%ld \n", i);
        i++;
    }
}

这个有效 - 评论我们的 while 循环:

#include <stdio.h>
#include <stdlib.h>

int main(void) {

    struct foo {
        int x;
        char s[5];
    };

    long size = 10000000;
    struct foo *bar[size];

    long i = 0;

    while (i < size) {
        //printf("%ld \n", i);
        i++;
    }

}

/* 我真正想要实现的是... SIGSEVS - 好的,谢谢你所有的回复,我真的很感激...... - 将查看 int 堆栈溢出并使用使用堆内存进行探索 - 谢谢大家 */

int main(void) {

struct foo {
    int x;
    char s[5];
};

long size = 10000000;
struct foo *bar[size];

long i = 0;
while (i < size) {
    bar[i] = (struct foo *) malloc(sizeof(struct foo));
    free(bar[i]);
    i++;
}
return EXIT_SUCCESS;

}

【问题讨论】:

  • 您的堆栈可能被限制为 8 MiB,因此当您尝试创建大于限制的本地数组时,您会崩溃。 while 循环的情况有点令人费解。编译器可能已经优化了所有内容。
  • 你是对的人......应该避免在堆栈上使用这么大的块 - 而在这种情况下我应该使用堆...... tnx man

标签: c


【解决方案1】:
long size = 10000000;
struct foo *bar[size];

将创建一个非常大的数组,这可能会导致堆栈溢出,因此您的程序会收到 SIGSEV。

你应该动态创建这个数组:

struct foo *bar = malloc(size * sizeof(struct foo *));

如果这些不是main()中的任何函数调用,为什么程序可以正常工作?

foo 的定义将导致main() 在运行时有一个大的堆栈帧。如果你不调用main()中的任何函数,这个大栈帧将不会被实际分配或访问(main()的入口代码只是通过操作一些寄存器和内存单元来确保保留一定的内存量);但是如果你调用main()中的函数,调用本身会尝试访问main()堆栈帧中的一些地址,因为堆栈溢出,这些地址可能无效,这将导致发送SIGSEV。

如果你反汇编并比较这个程序的工作和不工作版本,这将是显而易见的。也可以通过不工作main()的说明一一查出来。


main() 中没有函数调用:

0x00001ff0 <main+0>:    push   %ebp
0x00001ff1 <main+1>:    mov    %esp,%eax
0x00001ff3 <main+3>:    mov    %esp,%ebp
0x00001ff5 <main+5>:    sub    $0x2625a10,%esp
0x00001ffb <main+11>:   mov    %eax,%esp
0x00001ffd <main+13>:   leave  
0x00001ffe <main+14>:   ret  

main() 中致电exit()

0x00001fe0 <main+0>:    push   %ebp
0x00001fe1 <main+1>:    mov    %esp,%ebp
0x00001fe3 <main+3>:    sub    $0x2625a28,%esp
0x00001fe9 <main+9>:    movl   $0x0,(%esp)    <==== This causes segfault.
0x00001ff0 <main+16>:   call   0x3000 <dyld_stub_exit>

【讨论】:

  • 另外,检查是否bar == NULL。如果是这样,malloc() 调用失败。另外,稍后,通过free(bar);bar=NULL; 清理此内存
  • leeduhem - 但是为什么没有 while (printf) 循环,它可以工作?有什么想法吗?
  • @user3355469 如果你没有在你的main()中调用任何函数,foo的定义只会导致main()会有一个大的栈帧,但实际上并没有分配那个大的栈帧.但是,如果您调用main() 中的任何函数,则此调用本身将需要访问main() 堆栈帧的一部分,并且此访问将导致SIGSEV(因为尝试访问无效地址)。如果你反汇编不同版本的程序,并比较(或在 gdb 中执行指令步骤)它们,这很明显。
  • 我认为我应该使用 gdb - 但目前我只是使用 eclipse(尽管我认为它在后台使用 gdb 进行调试)......但也许我会使用 gdb 命令行获得更多内存可见性。 ..我还没有以这种方式使用过gdb...
【解决方案2】:

正如其他人指出的那样,堆栈大小是这里的问题。查看C/C++ maximum stack size of program了解更多详情。

【讨论】:

    【解决方案3】:

    堆栈溢出导致 sigsegv。不需要while循环。单个 printf 会导致堆栈溢出。
    局部变量是在堆栈上创建的。变量 foo 正在使用堆栈上的巨大空间。堆栈还用于存储函数调用中的返回地址。所以他们两个一起会导致堆栈溢出。 foo 几乎耗尽了堆栈中的所有空间。调用 printf 会溢出堆栈
    您应该使用 malloc 在堆上分配。

    【讨论】:

    • 嗨 v3ga - 你能详细说明一下吗?
    • 两件事 - 首先我怎么会事先知道这一点,其次是为什么如果我只是评论 printf,就像我在上面所做的编辑一样 - 它不 sigsev?
    • 没有人在栈上分配这么大的数组。你应该使用堆来分配这么大的数组。
    • 没有printf 很可能没有问题,因为实际上您从不使用该数组,因此编译器将其完全删除。实际答案可能仅来自分析编译器生成的确切内容的反汇编。
    • 非常感谢,我很感激 - 所以我想我在这里的主要事情是我确保我不会耗尽我的堆栈,并且我知道堆栈的限制 - 有没有一种编程方式我知道我达到堆栈限制了吗?