malloc()如何导致SIGSEGV?

时间:2009-09-17 19:59:55

标签: c gdb malloc sigsegv

我的程序中有一个奇怪的错误,在我看来malloc()正在引起一个SIGSEGV,据我所知,这没有任何意义。我正在使用一个名为simclist的库来创建动态列表。

这是稍后引用的结构:

typedef struct {
    int msgid;
    int status;
    void* udata;
    list_t queue;
} msg_t;

以下是代码:

msg_t* msg = (msg_t*) malloc( sizeof( msg_t ) );

msg->msgid = msgid;
msg->status = MSG_STAT_NEW;
msg->udata = udata;
list_init( &msg->queue );

list_init是程序失败的地方,这是list_init的代码:

/* list initialization */
int list_init(list_t *restrict l) {
    if (l == NULL) return -1;

    srandom((unsigned long)time(NULL));

    l->numels = 0;

    /* head/tail sentinels and mid pointer */
    l->head_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
    l->tail_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
    l->head_sentinel->next = l->tail_sentinel;
    l->tail_sentinel->prev = l->head_sentinel;
    l->head_sentinel->prev = l->tail_sentinel->next = l->mid = NULL;
    l->head_sentinel->data = l->tail_sentinel->data = NULL;

    /* iteration attributes */
    l->iter_active = 0;
    l->iter_pos = 0;
    l->iter_curentry = NULL;

    /* free-list attributes */
    l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS * sizeof(struct list_entry_s *));
    l->spareelsnum = 0;

#ifdef SIMCLIST_WITH_THREADS
    l->threadcount = 0;
#endif

    list_attributes_setdefaults(l);

    assert(list_repOk(l));
    assert(list_attrOk(l));

    return 0;
}

l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS *是根据堆栈跟踪引起SIGSEGV的地方。我正在使用gdb / nemiver进行调试,但我不知所措。第一次调用此函数时,它可以正常工作但第二次总是失败。 malloc()如何导致SIGSEGV?

这是堆栈跟踪:

#0  ?? () at :0
#1  malloc () at :0
#2  list_init (l=0x104f290) at src/simclist.c:205
#3  msg_new (msg_switch=0x1050dc0, msgid=8, udata=0x0) at src/msg_switch.c:218
#4  exread (sockfd=8, conn_info=0x104e0e0) at src/zimr-proxy/main.c:504
#5  zfd_select (tv_sec=0) at src/zfildes.c:124
#6  main (argc=3, argv=0x7fffcabe44f8) at src/zimr-proxy/main.c:210

非常感谢任何帮助或见解!

6 个答案:

答案 0 :(得分:26)

例如,当堆损坏时,

malloc会出现段错误。检查您是否正在编写超出先前分配范围的任何内容。

答案 1 :(得分:17)

代码的其他部分可能发生内存违规。如果你在Linux上,你一定要试试valgrind。我永远不会相信我自己的C程序,除非它通过valgrind。

编辑:另一个有用的工具是Electric fence。 Glibc还提供MALLOC_CHECK_环境变量来帮助调试内存问题。这两种方法不像valgrind那样影响运行速度。

答案 2 :(得分:12)

您可能在此调用之前通过缓冲区溢出或使用未由free(或已经释放)分配的指针调用malloc来损坏您的堆。

如果malloc使用的内部数据结构以这种方式被破坏,则malloc使用无效数据并可能崩溃。

答案 3 :(得分:4)

有多种方法可以从malloc()(以及realloc()calloc())触发核心转储。其中包括:

  • 缓冲区溢出:写入超出分配空间的末尾(践踏malloc()保留在那里的控制信息。)
  • 缓冲区下溢:在分配空间开始之前写入(践踏malloc()保留在那里的控制信息。)
  • 释放未由malloc()分配的内存。在混合的C和C ++程序中,这将包括释放new在C ++中分配的内存。
  • 释放指向malloc()分配的内存块的指针 - 这是前一种情况的特例。
  • 释放已经释放的指针 - 臭名昭着的“双重免费”。

在系统的标准版本中使用malloc()的诊断版本或启用诊断程序可能有助于识别其中一些问题。例如,它可能能够检测到小的下溢和溢出(因为它分配了额外的空间以在您请求的空间周围提供缓冲区),并且它可能检测到释放未分配或已释放的内存的尝试或者指向分配空间的一部分 - 因为它将与分配的空间分开存储信息。成本是调试版本占用更多空间。一个非常好的分配器将能够记录堆栈跟踪和行号,以告诉您代码中的分配位置,或第一次自由发生的位置。

答案 4 :(得分:1)

您应该尝试单独调试此代码,以查看问题是否实际位于生成segfault的位置。 (我怀疑它不是)。

这意味着:

#1:使用-O0编译代码,以确保gdb获得正确的行号信息。

#2:编写一个调用此部分代码的单元测试。

我的猜测是,单独使用时代码可以正常工作。然后,您可以以相同的方式测试其他模块,直到找到导致错误的原因。

正如其他人所建议的那样,使用Valgrind也是一个非常好的主意。

答案 5 :(得分:0)

代码有问题。如果malloc返回NULL,则在您的代码中无法正确处理此情况。你只是假设已经为你分配了实际上没有的内存。这可能会导致内存损坏。